Skip to content

Commit 9a5fdff

Browse files
committed
(beta) testing addon
1 parent 2aacb4c commit 9a5fdff

10 files changed

Lines changed: 1102 additions & 2 deletions

File tree

src/addons/addons/debugger/userscript.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,9 @@ export default async function ({ addon, console, msg }) {
518518
console,
519519
};
520520
logsTab = await createLogsTab(api);
521+
vm.runtime.on("CT_TEST_LOG", ({ text, type, thread }) => {
522+
logMessage(text, thread, type || "log");
523+
});
521524
const threadsTab = await createThreadsTab(api);
522525
const performanceTab = await createPerformanceTab(api);
523526
const allTabs = [logsTab, threadsTab, performanceTab];

src/containers/gui.jsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {postMessageToParent} from '../lib/ct-parent-message';
2+
import {installTestMessageListener} from '../lib/ct-test-messages';
23
import PropTypes from 'prop-types';
34
import React from 'react';
45
import {compose} from 'redux';
@@ -71,6 +72,8 @@ class GUI extends React.Component {
7172
if (window.location.pathname === '/' || window.location.pathname.indexOf('index.html') !== -1) {
7273
window.addEventListener('message', this.handleMessage);
7374
}
75+
76+
this.removeTestMessageListener = installTestMessageListener(this.props.vm);
7477
}
7578
componentDidUpdate (prevProps) {
7679
if (this.props.projectId !== prevProps.projectId) {
@@ -96,6 +99,10 @@ class GUI extends React.Component {
9699
}
97100
componentWillUnmount () {
98101
window.removeEventListener('message', this.handleMessage);
102+
if (this.removeTestMessageListener) {
103+
this.removeTestMessageListener();
104+
this.removeTestMessageListener = null;
105+
}
99106
}
100107
handleMessage (event) {
101108
if (event.data === 'REQUEST_SCREENSHOT') {

src/lib/ct-test-messages.js

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// REF:
2+
// Inbound: ct-list-tests, ct-run-tests, ct-cancel-tests
3+
// Outbound: ct-tests-available, ct-test-progress, ct-test-results, ct-test-error
4+
5+
import {getParentTargetOrigin, postMessageToParent} from './ct-parent-message';
6+
import {listTestNames, runTests} from './ct-test-runner';
7+
8+
/**
9+
* Whether a message that arrived from `origin` may drive the test runner.
10+
* @param {string} origin The event's origin.
11+
* @returns {boolean} True when the message is allowed.
12+
*/
13+
const isAllowedTestOrigin = origin => {
14+
const trusted = getParentTargetOrigin();
15+
if (trusted === '*') {
16+
return origin === window.location.origin;
17+
}
18+
return origin === trusted;
19+
};
20+
21+
/**
22+
* Tell the embedding page which tests this project has.
23+
* @param {object} vm The virtual machine.
24+
* @returns {void}
25+
*/
26+
const postTestsAvailable = vm => {
27+
postMessageToParent({
28+
type: 'ct-tests-available',
29+
runner: 'blocks',
30+
tests: listTestNames(vm.runtime)
31+
});
32+
};
33+
34+
/**
35+
* @param {?string} runId The run the error belongs to, if any.
36+
* @param {string} reason One of "busy", "no-project", "internal".
37+
* @param {string} [detail] Extra context.
38+
* @returns {void}
39+
*/
40+
const postTestError = (runId, reason, detail) => {
41+
const message = {
42+
type: 'ct-test-error',
43+
runId: typeof runId === 'string' ? runId : null,
44+
reason: reason
45+
};
46+
if (detail) {
47+
message.detail = detail;
48+
}
49+
postMessageToParent(message);
50+
};
51+
52+
/**
53+
* Listen for test messages from the embedding page, and answer them.
54+
*
55+
* @param {object} vm The virtual machine.
56+
* @returns {function} Call to stop listening.
57+
*/
58+
const installTestMessageListener = vm => {
59+
let activeRun = null;
60+
let activeRunId = null;
61+
62+
const startRun = data => {
63+
const runId = typeof data.runId === 'string' ? data.runId : null;
64+
if (activeRun) {
65+
postTestError(runId, 'busy', 'a test run is already in progress');
66+
return;
67+
}
68+
if (!vm.runtime || !vm.runtime.targets || vm.runtime.targets.length === 0) {
69+
postTestError(runId, 'no-project', 'no project is loaded');
70+
return;
71+
}
72+
activeRunId = runId;
73+
activeRun = runTests(vm, {
74+
timeoutMs: data.timeoutMs,
75+
onProgress: (index, total, test) => {
76+
postMessageToParent({
77+
type: 'ct-test-progress',
78+
runId: runId,
79+
index: index,
80+
total: total,
81+
test: test
82+
});
83+
}
84+
});
85+
activeRun.promise.then(report => {
86+
postMessageToParent({
87+
type: 'ct-test-results',
88+
runId: runId,
89+
report: report
90+
});
91+
}, error => {
92+
postTestError(runId, 'internal', String((error && error.message) || error));
93+
}).then(() => {
94+
activeRun = null;
95+
activeRunId = null;
96+
});
97+
};
98+
99+
const handleTestMessage = event => {
100+
const data = event.data;
101+
if (!data || typeof data.type !== 'string' || data.type.indexOf('ct-') !== 0) {
102+
return;
103+
}
104+
if (!isAllowedTestOrigin(event.origin)) {
105+
return;
106+
}
107+
switch (data.type) {
108+
case 'ct-list-tests':
109+
postTestsAvailable(vm);
110+
break;
111+
case 'ct-run-tests':
112+
startRun(data);
113+
break;
114+
case 'ct-cancel-tests':
115+
if (activeRun && (typeof data.runId !== 'string' || data.runId === activeRunId)) {
116+
activeRun.cancel();
117+
}
118+
break;
119+
default:
120+
break;
121+
}
122+
};
123+
124+
const handleProjectLoaded = () => {
125+
postTestsAvailable(vm);
126+
};
127+
128+
window.addEventListener('message', handleTestMessage);
129+
if (vm.runtime && typeof vm.runtime.on === 'function') {
130+
vm.runtime.on('PROJECT_LOADED', handleProjectLoaded);
131+
}
132+
133+
return () => {
134+
window.removeEventListener('message', handleTestMessage);
135+
if (vm.runtime && typeof vm.runtime.removeListener === 'function') {
136+
vm.runtime.removeListener('PROJECT_LOADED', handleProjectLoaded);
137+
}
138+
if (activeRun) {
139+
activeRun.cancel();
140+
}
141+
};
142+
};
143+
144+
export {
145+
installTestMessageListener,
146+
isAllowedTestOrigin,
147+
postTestsAvailable
148+
};

0 commit comments

Comments
 (0)