Skip to content

Commit b360d8a

Browse files
mydeabillyvg
authored andcommitted
test: Refactor playwright bundle generation (#8029)
1 parent 4570508 commit b360d8a

File tree

12 files changed

+152
-100
lines changed

12 files changed

+152
-100
lines changed

.prettierignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
*.md
22
.nxcache
3-
packages/browser-integration-tests/fixtures

packages/browser-integration-tests/.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module.exports = {
1111
'loader-suites/**/subject.js',
1212
'scripts/**',
1313
'fixtures/**',
14+
'tmp/**',
1415
],
1516
parserOptions: {
1617
sourceType: 'module',
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
test-results
2+
tmp
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
tmp
2+
fixtures

packages/browser-integration-tests/loader-suites/loader/noOnLoad/sdkLoadedInMeanwhile/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import fs from 'fs';
33
import path from 'path';
44

55
import { sentryTest, TEST_HOST } from '../../../../utils/fixtures';
6-
import { LOADER_CONFIGS } from '../../../../utils/generatePage';
6+
import { LOADER_CONFIGS } from '../../../../utils/generatePlugin';
77
import { envelopeRequestParser, waitForErrorRequest } from '../../../../utils/helpers';
88

99
const bundle = process.env.PW_BUNDLE || '';

packages/browser-integration-tests/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
},
99
"private": true,
1010
"scripts": {
11-
"clean": "rimraf -g suites/**/dist loader-suites/**/dist",
11+
"clean": "rimraf -g suites/**/dist loader-suites/**/dist tmp",
1212
"install-browsers": "playwright install --with-deps",
1313
"lint": "run-s lint:prettier lint:eslint",
1414
"lint:eslint": "eslint . --format stylish",
@@ -58,6 +58,7 @@
5858
},
5959
"devDependencies": {
6060
"@types/glob": "8.0.0",
61+
"@types/node": "^14.6.4",
6162
"glob": "8.0.3"
6263
},
6364
"volta": {

packages/browser-integration-tests/playwright.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@ const config: PlaywrightTestConfig = {
77
// Use 3 workers on CI, else use defaults (based on available CPU cores)
88
// Note that 3 is a random number selected to work well with our CI setup
99
workers: process.env.CI ? 3 : undefined,
10+
11+
globalSetup: require.resolve('./playwright.setup.ts'),
1012
};
13+
1114
export default config;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import setupStaticAssets from './utils/staticAssets';
2+
3+
export default function globalSetup(): Promise<void> {
4+
return setupStaticAssets();
5+
}

packages/browser-integration-tests/utils/fixtures.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { test as base } from '@playwright/test';
33
import fs from 'fs';
44
import path from 'path';
55

6-
import { generateLoader, generatePage } from './generatePage';
6+
import { generatePage } from './generatePage';
77

88
export const TEST_HOST = 'http://sentry-test.io';
99

@@ -53,7 +53,6 @@ const sentryTest = base.extend<TestFixtures>({
5353
const pagePath = `${TEST_HOST}/index.html`;
5454

5555
await build(testDir);
56-
generateLoader(testDir);
5756

5857
// Serve all assets under
5958
if (!skipRouteHandler) {

packages/browser-integration-tests/utils/generatePage.ts

Lines changed: 2 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,10 @@
1-
import { existsSync, mkdirSync, readFileSync, symlinkSync, unlinkSync, writeFileSync } from 'fs';
1+
import { existsSync, mkdirSync } from 'fs';
22
import HtmlWebpackPlugin from 'html-webpack-plugin';
3-
import path from 'path';
43
import webpack from 'webpack';
54

65
import webpackConfig from '../webpack.config';
7-
import { TEST_HOST } from './fixtures';
86
import SentryScenarioGenerationPlugin from './generatePlugin';
97

10-
const LOADER_TEMPLATE = readFileSync(path.join(__dirname, '../fixtures/loader.js'), 'utf-8');
11-
12-
export const LOADER_CONFIGS: Record<string, { bundle: string; options: Record<string, unknown>; lazy: boolean }> = {
13-
loader_base: {
14-
bundle: 'browser/build/bundles/bundle.es5.min.js',
15-
options: {},
16-
lazy: true,
17-
},
18-
loader_eager: {
19-
bundle: 'browser/build/bundles/bundle.es5.min.js',
20-
options: {},
21-
lazy: false,
22-
},
23-
loader_debug: {
24-
bundle: 'browser/build/bundles/bundle.es5.debug.min.js',
25-
options: { debug: true },
26-
lazy: true,
27-
},
28-
loader_tracing: {
29-
bundle: 'browser/build/bundles/bundle.tracing.es5.min.js',
30-
options: { tracesSampleRate: 1 },
31-
lazy: false,
32-
},
33-
loader_replay: {
34-
bundle: 'browser/build/bundles/bundle.replay.min.js',
35-
options: { replaysSessionSampleRate: 1, replaysOnErrorSampleRate: 1 },
36-
lazy: false,
37-
},
38-
loader_tracing_replay: {
39-
bundle: 'browser/build/bundles/bundle.tracing.replay.debug.min.js',
40-
options: { tracesSampleRate: 1, replaysSessionSampleRate: 1, replaysOnErrorSampleRate: 1, debug: true },
41-
lazy: false,
42-
},
43-
};
44-
45-
const bundleKey = process.env.PW_BUNDLE || '';
46-
47-
export function generateLoader(outPath: string): void {
48-
const localPath = `${outPath}/dist`;
49-
50-
if (!existsSync(localPath)) {
51-
return;
52-
}
53-
54-
// Generate loader files
55-
const loaderConfig = LOADER_CONFIGS[bundleKey];
56-
57-
if (!loaderConfig) {
58-
throw new Error(`Unknown loader bundle key: ${bundleKey}`);
59-
}
60-
61-
const localCdnBundlePath = path.join(localPath, 'cdn.bundle.js');
62-
63-
try {
64-
unlinkSync(localCdnBundlePath);
65-
} catch {
66-
// ignore if this didn't exist
67-
}
68-
69-
const cdnSourcePath = path.resolve(__dirname, `../../${loaderConfig.bundle}`);
70-
symlinkSync(cdnSourcePath, localCdnBundlePath);
71-
72-
const loaderPath = path.join(localPath, 'loader.js');
73-
const loaderContent = LOADER_TEMPLATE.replace('__LOADER_BUNDLE__', `'${TEST_HOST}/cdn.bundle.js'`)
74-
.replace(
75-
'__LOADER_OPTIONS__',
76-
JSON.stringify({
77-
dsn: 'https://[email protected]/1337',
78-
...loaderConfig.options,
79-
}),
80-
)
81-
.replace('__LOADER_LAZY__', loaderConfig.lazy ? 'true' : 'false');
82-
83-
writeFileSync(loaderPath, loaderContent, 'utf-8');
84-
}
85-
868
export async function generatePage(
879
initPath: string,
8810
subjectPath: string,
@@ -110,7 +32,7 @@ export async function generatePage(
11032
filename: '[name].bundle.js',
11133
},
11234
plugins: [
113-
new SentryScenarioGenerationPlugin(),
35+
new SentryScenarioGenerationPlugin(localPath),
11436
new HtmlWebpackPlugin({
11537
filename: outPageName,
11638
template: templatePath,

packages/browser-integration-tests/utils/generatePlugin.ts

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import HtmlWebpackPlugin, { createHtmlTagObject } from 'html-webpack-plugin';
44
import path from 'path';
55
import type { Compiler } from 'webpack';
66

7+
import { addStaticAsset, addStaticAssetSymlink } from './staticAssets';
8+
9+
const LOADER_TEMPLATE = fs.readFileSync(path.join(__dirname, '../fixtures/loader.js'), 'utf-8');
710
const PACKAGES_DIR = '../../packages';
811

912
/**
@@ -34,6 +37,12 @@ const BUNDLE_PATHS: Record<string, Record<string, string>> = {
3437
bundle_tracing_es6_min: 'build/bundles/bundle.tracing.min.js',
3538
bundle_tracing_replay_es6: 'build/bundles/bundle.tracing.replay.js',
3639
bundle_tracing_replay_es6_min: 'build/bundles/bundle.tracing.replay.min.js',
40+
loader_base: 'build/bundles/bundle.es5.min.js',
41+
loader_eager: 'build/bundles/bundle.es5.min.js',
42+
loader_debug: 'build/bundles/bundle.es5.debug.min.js',
43+
loader_tracing: 'build/bundles/bundle.tracing.es5.min.js',
44+
loader_replay: 'build/bundles/bundle.replay.min.js',
45+
loader_tracing_replay: 'build/bundles/bundle.tracing.replay.debug.min.js',
3746
},
3847
integrations: {
3948
cjs: 'build/npm/cjs/index.js',
@@ -51,6 +60,33 @@ const BUNDLE_PATHS: Record<string, Record<string, string>> = {
5160
},
5261
};
5362

63+
export const LOADER_CONFIGS: Record<string, { options: Record<string, unknown>; lazy: boolean }> = {
64+
loader_base: {
65+
options: {},
66+
lazy: true,
67+
},
68+
loader_eager: {
69+
options: {},
70+
lazy: false,
71+
},
72+
loader_debug: {
73+
options: { debug: true },
74+
lazy: true,
75+
},
76+
loader_tracing: {
77+
options: { tracesSampleRate: 1 },
78+
lazy: false,
79+
},
80+
loader_replay: {
81+
options: { replaysSessionSampleRate: 1, replaysOnErrorSampleRate: 1 },
82+
lazy: false,
83+
},
84+
loader_tracing_replay: {
85+
options: { tracesSampleRate: 1, replaysSessionSampleRate: 1, replaysOnErrorSampleRate: 1, debug: true },
86+
lazy: false,
87+
},
88+
};
89+
5490
/*
5591
* Generate webpack aliases based on packages in monorepo
5692
*
@@ -97,9 +133,14 @@ function generateSentryAlias(): Record<string, string> {
97133
class SentryScenarioGenerationPlugin {
98134
public requiredIntegrations: string[] = [];
99135
public requiresWASMIntegration: boolean = false;
136+
public localOutPath: string;
100137

101138
private _name: string = 'SentryScenarioGenerationPlugin';
102139

140+
public constructor(localOutPath: string) {
141+
this.localOutPath = localOutPath;
142+
}
143+
103144
public apply(compiler: Compiler): void {
104145
compiler.options.resolve.alias = generateSentryAlias();
105146
compiler.options.externals = useBundleOrLoader
@@ -136,20 +177,34 @@ class SentryScenarioGenerationPlugin {
136177
const bundleName = 'browser';
137178
const bundlePath = BUNDLE_PATHS[bundleName][bundleKey];
138179

139-
let bundleObject =
140-
bundlePath &&
141-
createHtmlTagObject('script', {
142-
src: path.resolve(PACKAGES_DIR, bundleName, bundlePath),
143-
});
144-
145-
if (!bundleObject && useLoader) {
146-
bundleObject = createHtmlTagObject('script', {
147-
src: 'loader.js',
148-
});
180+
if (!bundlePath) {
181+
throw new Error(`Could not find bundle or loader for key ${bundleKey}`);
149182
}
150183

151-
if (!bundleObject) {
152-
throw new Error(`Could not find bundle or loader for key ${bundleKey}`);
184+
const bundleObject = useLoader
185+
? createHtmlTagObject('script', {
186+
src: 'loader.js',
187+
})
188+
: createHtmlTagObject('script', {
189+
src: 'cdn.bundle.js',
190+
});
191+
192+
addStaticAssetSymlink(this.localOutPath, path.resolve(PACKAGES_DIR, bundleName, bundlePath), 'cdn.bundle.js');
193+
194+
if (useLoader) {
195+
const loaderConfig = LOADER_CONFIGS[bundleKey];
196+
197+
addStaticAsset(this.localOutPath, 'loader.js', () => {
198+
return LOADER_TEMPLATE.replace('__LOADER_BUNDLE__', "'/cdn.bundle.js'")
199+
.replace(
200+
'__LOADER_OPTIONS__',
201+
JSON.stringify({
202+
dsn: 'https://[email protected]/1337',
203+
...loaderConfig.options,
204+
}),
205+
)
206+
.replace('__LOADER_LAZY__', loaderConfig.lazy ? 'true' : 'false');
207+
});
153208
}
154209

155210
// Convert e.g. bundle_tracing_es5_min to bundle_es5_min
@@ -159,20 +214,33 @@ class SentryScenarioGenerationPlugin {
159214
.replace('_tracing', '');
160215

161216
this.requiredIntegrations.forEach(integration => {
162-
const integrationObject = createHtmlTagObject('script', {
163-
src: path.resolve(
217+
const fileName = `${integration}.bundle.js`;
218+
addStaticAssetSymlink(
219+
this.localOutPath,
220+
path.resolve(
164221
PACKAGES_DIR,
165222
'integrations',
166223
BUNDLE_PATHS['integrations'][integrationBundleKey].replace('[INTEGRATION_NAME]', integration),
167224
),
225+
fileName,
226+
);
227+
228+
const integrationObject = createHtmlTagObject('script', {
229+
src: fileName,
168230
});
169231

170232
data.assetTags.scripts.unshift(integrationObject);
171233
});
172234

173235
if (this.requiresWASMIntegration && BUNDLE_PATHS['wasm'][integrationBundleKey]) {
236+
addStaticAssetSymlink(
237+
this.localOutPath,
238+
path.resolve(PACKAGES_DIR, 'wasm', BUNDLE_PATHS['wasm'][integrationBundleKey]),
239+
'wasm.bundle.js',
240+
);
241+
174242
const wasmObject = createHtmlTagObject('script', {
175-
src: path.resolve(PACKAGES_DIR, 'wasm', BUNDLE_PATHS['wasm'][integrationBundleKey]),
243+
src: 'wasm.bundle.js',
176244
});
177245

178246
data.assetTags.scripts.unshift(wasmObject);
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import fs from 'fs';
2+
import path from 'path';
3+
4+
export const STATIC_DIR = path.join(__dirname, '../tmp/static');
5+
6+
export default async function setupStaticAssets(): Promise<void> {
7+
if (fs.existsSync(STATIC_DIR)) {
8+
await fs.promises.rm(STATIC_DIR, { recursive: true });
9+
}
10+
11+
await fs.promises.mkdir(STATIC_DIR, { recursive: true });
12+
}
13+
14+
export function addStaticAsset(localOutPath: string, fileName: string, cb: () => string): void {
15+
const newPath = path.join(STATIC_DIR, fileName);
16+
17+
// Only copy files once
18+
if (!fs.existsSync(newPath)) {
19+
fs.writeFileSync(newPath, cb(), 'utf-8');
20+
}
21+
22+
symlinkAsset(newPath, path.join(localOutPath, fileName));
23+
}
24+
25+
export function addStaticAssetSymlink(localOutPath: string, originalPath: string, fileName: string): void {
26+
const newPath = path.join(STATIC_DIR, fileName);
27+
28+
// Only copy files once
29+
if (!fs.existsSync(newPath)) {
30+
fs.symlinkSync(originalPath, newPath);
31+
}
32+
33+
symlinkAsset(newPath, path.join(localOutPath, fileName));
34+
}
35+
36+
function symlinkAsset(originalPath: string, targetPath: string): void {
37+
try {
38+
fs.unlinkSync(targetPath);
39+
} catch {
40+
// ignore errors here
41+
}
42+
43+
try {
44+
fs.linkSync(originalPath, targetPath);
45+
} catch (error) {
46+
// only ignore these kind of errors
47+
if (!`${error}`.includes('file already exists')) {
48+
throw error;
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)