-
Notifications
You must be signed in to change notification settings - Fork 85
Expand file tree
/
Copy pathrun-umd-tests.js
More file actions
executable file
·294 lines (257 loc) · 9.64 KB
/
Copy pathrun-umd-tests.js
File metadata and controls
executable file
·294 lines (257 loc) · 9.64 KB
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
#!/usr/bin/env node
/**
* Copyright 2025, Optimizely
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const { execSync } = require('child_process');
const browserstack = require('browserstack-local');
const fs = require('fs');
const path = require('path');
// Browser configurations grouped by browser name
const BROWSER_CONFIGS = {
chrome: [
{ name: 'chrome-102-windows', browserVersion: '102', os: 'Windows', osVersion: '11' },
{ name: 'chrome-latest-windows', browserVersion: 'latest', os: 'Windows', osVersion: '11' },
],
firefox: [
{ name: 'firefox-91-windows', browserVersion: '91', os: 'Windows', osVersion: '11' },
{ name: 'firefox-latest-windows', browserVersion: 'latest', os: 'Windows', osVersion: '11' },
],
edge: [
{ name: 'edge-89-windows', browserVersion: '89', os: 'Windows', osVersion: '11' },
{ name: 'edge-latest-windows', browserVersion: 'latest', os: 'Windows', osVersion: '11' },
],
safari: [
{ name: 'safari-monterey', os: 'OS X', osVersion: 'Monterey' },
{ name: 'safari-sequoia', os: 'OS X', osVersion: 'Sequoia' },
]
};
// Determine if we should use local browser or BrowserStack
// Priority: USE_LOCAL_BROWSER env var, then check for BrowserStack credentials
let useLocalBrowser = process.env.USE_LOCAL_BROWSER === 'true';
if (!useLocalBrowser) {
// Check for BrowserStack credentials
const username = process.env.BROWSERSTACK_USERNAME || process.env.BROWSER_STACK_USERNAME;
const accessKey = process.env.BROWSERSTACK_ACCESS_KEY || process.env.BROWSER_STACK_ACCESS_KEY;
console.log('\n' + '='.repeat(80));
console.log('BrowserStack Credentials Check:');
console.log('='.repeat(80));
console.log(`BROWSERSTACK_USERNAME: ${username ? '✓ Available' : '✗ Not found'}`);
console.log(`BROWSERSTACK_ACCESS_KEY: ${accessKey ? '✓ Available' : '✗ Not found'}`);
console.log('='.repeat(80) + '\n');
if (!username || !accessKey) {
console.log('BrowserStack credentials not found - falling back to local browser mode');
useLocalBrowser = true;
}
}
let bs_local = null;
function startTunnel(localIdentifier) {
const accessKey = process.env.BROWSERSTACK_ACCESS_KEY || process.env.BROWSER_STACK_ACCESS_KEY;
console.log(`Starting BrowserStack Local tunnel with identifier: ${localIdentifier}...`);
bs_local = new browserstack.Local();
const bsLocalArgs = {
key: accessKey,
force: true,
forceLocal: true,
// Enable verbose logging to debug tunnel issues
verbose: true,
// Use the provided identifier for parallel tunnel support
localIdentifier: localIdentifier,
};
return new Promise((resolve, reject) => {
bs_local.start(bsLocalArgs, (error) => {
if (error) {
console.error('Error starting BrowserStack Local:', error);
reject(error);
} else {
console.log('BrowserStack Local tunnel started successfully');
console.log(`BrowserStack Local PID: ${bs_local.pid}`);
console.log(`Local Identifier: ${localIdentifier}`);
// Wait longer for tunnel to fully establish and register with BrowserStack
console.log('Waiting for tunnel to establish...');
setTimeout(() => {
console.log('Tunnel ready!');
resolve();
}, 10000);
}
});
});
}
function stopTunnel() {
if (!bs_local) {
return Promise.resolve();
}
return new Promise((resolve) => {
bs_local.stop(() => {
console.log('BrowserStack Local tunnel stopped');
resolve();
});
});
}
async function runTests() {
let exitCode = 0;
try {
// Step 1: Run npm run build
console.log('\n' + '='.repeat(80));
console.log('Building project...');
console.log('='.repeat(80));
try {
execSync('npm run build-browser-umd', { stdio: 'inherit' });
console.log('Build completed successfully!');
} catch (error) {
console.error('Failed to build project:', error.message);
exitCode = 1;
return;
}
// Step 2: Copy the UMD file to vitest/public/dist/
console.log('\n' + '='.repeat(80));
console.log('Copying UMD file to vitest/public/dist/...');
console.log('='.repeat(80));
try {
const sourceFile = path.join(process.cwd(), 'dist/optimizely.browser.umd.min.js');
const destDir = path.join(process.cwd(), 'vitest/public/dist');
const destFile = path.join(destDir, 'optimizely.browser.umd.min.js');
// Create destination directory if it doesn't exist
if (!fs.existsSync(destDir)) {
fs.mkdirSync(destDir, { recursive: true });
console.log(`Created directory: ${destDir}`);
}
// Copy the file
fs.copyFileSync(sourceFile, destFile);
console.log(`Copied ${sourceFile} to ${destFile}`);
} catch (error) {
console.error('Failed to copy UMD file:', error.message);
exitCode = 1;
return;
}
// Patch Vitest viewport command to prevent WebDriver Bidi errors
console.log('\n' + '='.repeat(80));
console.log('Patching Vitest viewport command...');
console.log('='.repeat(80));
try {
execSync('node ./scripts/patch-vitest-viewport.js', { stdio: 'inherit' });
} catch (error) {
console.error('Failed to patch Vitest viewport command:', error.message);
exitCode = 1;
return;
}
// Get browser name from environment variable (default to chrome)
const browserName = (process.env.TEST_BROWSER || 'chrome').toLowerCase();
let configs;
if (useLocalBrowser) {
configs = [{
name: `${browserName}`,
}];
console.log('Local browser mode: using local browser installation');
} else {
// For BrowserStack, use the defined configs
configs = BROWSER_CONFIGS[browserName];
if (!configs || configs.length === 0) {
console.error(`Error: No configurations found for browser '${browserName}'`);
console.error(`Available browsers: ${Object.keys(BROWSER_CONFIGS).join(', ')}`);
exitCode = 1;
return;
}
}
// Only start tunnel if using BrowserStack
let localIdentifier;
if (!useLocalBrowser) {
// Generate a random identifier for parallel tunnel support (100000-900000)
localIdentifier = Math.floor(Math.random() * 800000) + 100000;
localIdentifier = localIdentifier.toString();
await startTunnel(localIdentifier);
} else {
console.log('Using local browser mode - no BrowserStack connection needed');
}
console.log('\n' + '='.repeat(80));
console.log(`Running UMD tests for browser: ${browserName}`);
console.log(`Total configurations: ${configs.length}`);
console.log('='.repeat(80) + '\n');
const results = [];
// Run each config serially
for (const config of configs) {
console.log(`\n${'='.repeat(80)}`);
console.log(`Running: ${config.name}`);
console.log(`Browser: ${browserName}${config.browserVersion ? ` ${config.browserVersion}` : ''}`);
console.log(`OS: ${config.os} ${config.osVersion}`);
console.log('='.repeat(80));
// Set environment variables for this config
const env = {
...process.env,
TEST_BROWSER: browserName,
TEST_BROWSER_VERSION: config.browserVersion,
TEST_OS_NAME: config.os,
TEST_OS_VERSION: config.osVersion,
// Pass the local identifier to vitest config for BrowserStack capabilities
BROWSERSTACK_LOCAL_IDENTIFIER: localIdentifier,
};
try {
console.log('Starting vitest UMD test...');
// Run vitest with the UMD config
execSync('npm run test-vitest -- --config vitest.umd.config.mts', {
stdio: 'inherit',
env,
});
console.log(`\n✓ ${config.name} passed!`);
results.push({ config: config.name, success: true });
} catch (error) {
console.error(`\n✗ ${config.name} failed`);
if (error.message) {
console.error('Error message:', error.message);
}
results.push({ config: config.name, success: false });
}
}
// Print summary
console.log('\n' + '='.repeat(80));
console.log(`UMD test summary for ${browserName}:`);
console.log('='.repeat(80));
const failures = [];
const successes = [];
results.forEach(({ config, success }) => {
if (success) {
successes.push(config);
console.log(`✓ ${config}: PASSED`);
} else {
failures.push(config);
console.error(`✗ ${config}: FAILED`);
}
});
console.log('='.repeat(80));
console.log(`Total: ${results.length} configurations`);
console.log(`Passed: ${successes.length}`);
console.log(`Failed: ${failures.length}`);
console.log('='.repeat(80));
// Set exit code based on results
if (failures.length > 0) {
console.error(`\nSome ${browserName} configurations failed. See above for details.`);
exitCode = 1;
} else {
console.log(`\nAll ${browserName} configurations passed!`);
exitCode = 0;
}
} finally {
// Only stop tunnel if using BrowserStack
if (!useLocalBrowser) {
await stopTunnel();
}
// Exit after tunnel is properly closed
process.exit(exitCode);
}
}
// Run the tests
runTests().catch((error) => {
console.error('Fatal error:', error);
process.exit(1);
});