forked from tinymce/tinymce
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Gruntfile.js
224 lines (193 loc) · 7.34 KB
/
Gruntfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
// Tests always run in a browser, but some we run headless
const runsHeadless = [
'@ephox/alloy',
'@ephox/mcagar',
'@ephox/katamari',
'@ephox/katamari-test',
'@ephox/jax'
];
if (!Array.prototype.flatMap) {
// simple polyfill for node versions < 11
// not at all to ES2019 spec, but if you're relying on that you should use node 11 /shrug
const concat = (x, y) => x.concat(y);
const flatMap = (f, xs) => xs.map(f).reduce(concat, []);
Array.prototype.flatMap = function (f) {
return flatMap(f, this);
};
}
const filterChanges = (changes, tests) => {
return changes.filter((change => tests.indexOf(change.name) > -1));
};
const filterChangesNot = (changes, badTests) => {
return changes.filter((change => badTests.indexOf(change.name) === -1));
};
/* structure of lerna output
{
name: string,
version: string,
private: boolean,
location: string
}
*/
/** Note: this is optimized for speed. Turns out globbing in node.js is time-consuming.
* Restrict tinymce to 2 arbitrary levels of test base folders.
* All other projects need their tests in src/test/ts
*/
const testFolders = (tests, auto) => tests.flatMap((test) => {
const testTypes = ['atomic', 'browser', 'headless'].concat(auto ? ['webdriver'] : []);
const bases = test.name === "tinymce" ? ["src/*/test/ts", "src/*/*/test/ts"] : ["src/test/ts"];
return bases.flatMap(base => testTypes.map(tt => `${test.location}/${base}/${tt}/**/*Test.ts`));
});
const bedrockDefaults = {
config: 'tsconfig.json',
customRoutes: 'modules/tinymce/src/core/test/json/routes.json',
overallTimeout: 180000,
singleTimeout: 60000,
};
const bedrockHeadless = (tests, browser, auto) => {
if (tests.length === 0) {
return {};
} else {
return {
headless: {
...bedrockDefaults,
name: 'headless-tests',
browser,
useSelenium: true,
testfiles: testFolders(tests, auto),
// we have a few tests that don't play nicely when combined together in the monorepo
retries: 3
}
}
}
};
const bedrockBrowser = (tests, browserName, osName, bucket, buckets, chunk, remote, auto, opts) => {
const name = opts.name ? opts.name : `${browserName}-${osName}`;
if (tests.length === 0) {
return {};
} else {
return {
browser: {
...bedrockDefaults,
overallTimeout: 3600000,
name: name,
browser: browserName,
testfiles: testFolders(tests, auto),
bucket: bucket,
buckets: buckets,
chunk: chunk,
remote: remote,
// we have a few tests that don't play nicely when combined together in the monorepo
retries: 3,
...opts
}
};
}
};
const fetchLernaProjects = (log, runAllTests) => {
// This has to be sync because grunt can't do async config
var exec = require('child_process').execSync;
// if JSON parse fails, well, grunt will just fail /shrug
const parseLernaList = (cmd) => {
try {
return JSON.parse(exec(`yarn -s lerna ${cmd} -a --json --loglevel warn 2>&1`));
} catch (e) {
// If no changes are found, then lerna returns an exit code of 1, so deal with that gracefully
if (e.status === 1) {
return [];
} else {
throw e;
}
}
};
const changes = runAllTests ? [] : parseLernaList('changed --no-ignore-changes');
if (changes.length === 0) {
log.writeln('No changes found, testing all projects');
// If there are no changes, use "lerna list" instead of "lerna changed" to test everything
return parseLernaList('list');
} else {
return changes;
}
};
module.exports = function (grunt) {
const runAllTests = grunt.option('ignore-lerna-changed') || false;
const changes = fetchLernaProjects(grunt.log, runAllTests);
const bucket = parseInt(grunt.option('bucket'), 10) || 1;
const buckets = parseInt(grunt.option('buckets'), 10) || 1;
const chunk = parseInt(grunt.option('chunk'), 10) || 100;
const headlessTests = filterChanges(changes, runsHeadless);
const browserTests = filterChangesNot(changes, runsHeadless);
const activeBrowser = grunt.option('bedrock-browser') || 'chrome-headless';
const headlessBrowser = activeBrowser.endsWith("-headless") ? activeBrowser : 'chrome-headless';
const activeOs = grunt.option('bedrock-os') || 'tests';
const remote = grunt.option('remote');
const bedrockOpts = (grunt, availableOpts) => {
return availableOpts.reduce((opts, opt) => {
const current = grunt.option(opt);
if (current) opts[opt] = current;
return opts;
}, {});
};
const opts = bedrockOpts(grunt, ['name', 'username', 'accesskey', 'sishDomain', 'devicefarmArn', 'devicefarmRegion', 'platformName', 'browserVersion']);
const gruntConfig = {
shell: {
tsc: { command: 'yarn -s tsc' },
legacy: { command: 'yarn build' },
yarn: { command: 'yarn' },
'yarn-dev': { command: 'yarn -s dev' }
},
'bedrock-auto': {
...bedrockHeadless(headlessTests, headlessBrowser, true),
...bedrockBrowser(browserTests, activeBrowser, activeOs, bucket, buckets, chunk, remote, true, opts)
},
'bedrock-manual': {
...bedrockHeadless(headlessTests, headlessBrowser, false),
...bedrockBrowser(browserTests, activeBrowser, activeOs, bucket, buckets, chunk, remote, false, opts)
}
};
// console.log(JSON.stringify(gruntConfig, null, 2))
grunt.initConfig(gruntConfig);
//TODO: remove duplication
if (headlessTests.length > 0) {
grunt.registerTask('list-changed-headless', () => {
const changeList = JSON.stringify(headlessTests.reduce((acc, change) => acc.concat(change.name), []), null, 2);
grunt.log.writeln('Changed projects for headless testing:', changeList);
});
grunt.registerTask('headless-auto', ['list-changed-headless', 'shell:tsc', 'bedrock-auto:headless']);
grunt.registerTask('headless-manual', ['list-changed-headless', 'shell:tsc', 'bedrock-manual:headless']);
} else {
const noHeadless = () => {
grunt.log.writeln('no changed modules need headless testing');
};
grunt.registerTask('headless-auto', noHeadless);
grunt.registerTask('headless-manual', noHeadless);
grunt.registerTask('list-changed-headless', noHeadless);
}
//TODO: remove duplication
if (browserTests.length > 0) {
grunt.registerTask('list-changed-browser', () => {
const changeList = JSON.stringify(browserTests.reduce((acc, change) => acc.concat(change.name), []), null, 2);
grunt.log.writeln('Changed projects for browser testing:', changeList);
});
grunt.registerTask('browser-auto', ['list-changed-browser', 'shell:tsc', 'bedrock-auto:browser']);
grunt.registerTask('browser-manual', ['list-changed-browser', 'shell:tsc', 'bedrock-manual:browser']);
} else {
const noBrowser = () => {
grunt.log.writeln('no changed modules need browser testing');
};
grunt.registerTask('browser-auto', noBrowser);
grunt.registerTask('browser-manual', noBrowser);
grunt.registerTask('list-changed-browser', noBrowser);
}
grunt.registerTask('legacy-warn', () => grunt.log.warn(`
*******
Top-level grunt has been replaced by 'yarn build', and the output has moved from project root to modules/tinymce
*******
`));
grunt.registerTask('default', ['legacy-warn', 'shell:legacy']);
require('load-grunt-tasks')(grunt, {
requireResolution: true,
config: 'package.json',
pattern: ['@ephox/bedrock-server', 'grunt-shell']
});
};