@amazon/vinyl-build-utils 3.0.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,123 +0,0 @@
1
- import type { ServerOptions } from '../express/serve';
2
- import type { BrowserDetails, BrowserStackCredentials, WorkerOptions } from './browserStackRestApi';
3
- import type { Options as BsLocalOptions } from 'browserstack-local';
4
- import type { BrowserStackWorkerControllerOptions } from './BrowserStackWorkerController';
5
- import { LogLevel } from '../util/Logger';
6
- export interface BrowserStackOptions extends BrowserStackWorkerControllerOptions {
7
- /**
8
- * BrowserStack local connection options.
9
- */
10
- readonly local?: Partial<BsLocalOptions>;
11
- /**
12
- * Local server configuration.
13
- */
14
- readonly server: ServerOptions;
15
- /**
16
- * The BrowserStack credentials, if undefined these will be taken from the environment variables
17
- * BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY.
18
- * If a `.env` file exists, it will be used to populate environmental variables.
19
- */
20
- readonly credentials?: BrowserStackCredentials | Promise<BrowserStackCredentials>;
21
- /**
22
- * The list of browsers to test against.
23
- * `name` if not provided will be generated using '<device> <os> <browser> <browser_version>'.
24
- *
25
- * Valid browsers and devices can be obtained using the SDK config generator at:
26
- * {@link https://www.browserstack.com/docs/automate/selenium/sdk-config-generator}
27
- */
28
- readonly browsers: readonly WorkerInitOptions[];
29
- /**
30
- * Options common to all workers.
31
- *
32
- * `build` will default to a unique identifier if not provided.
33
- */
34
- readonly workerCommon?: CommonWorkerInitOptions;
35
- /**
36
- * If true, shows continuous progress in the console.
37
- * If false, progress will be logged in at most 10% increments.
38
- *
39
- * Recommended to set to false for CI environments.
40
- * Default: true when the process.stdout is a terminal.
41
- */
42
- readonly stickyProgress?: boolean;
43
- /**
44
- * If true, terminates all workers on the first failure.
45
- * Default: false
46
- */
47
- readonly stopOnFirstFailure?: boolean;
48
- /**
49
- * Sets the log verbosity.
50
- * Default: LogLevel.INFO
51
- */
52
- readonly logLevel?: LogLevel;
53
- }
54
- /**
55
- * Options to be used as defaults for all workers.
56
- * Values set on the worker will take priority.
57
- */
58
- export type CommonWorkerInitOptions = Omit<WorkerInitOptions, keyof BrowserDetails>;
59
- export interface WorkerInitOptions extends Omit<WorkerOptions, 'url'> {
60
- /**
61
- * A valid url to navigate the browser to.
62
- * If not set, the local server URL will be used.
63
- */
64
- readonly url?: string;
65
- }
66
- /**
67
- * Attempts to get the BrowserStackCredentials from the environment.
68
- */
69
- export declare function getEnvBrowserStackCredentials(): BrowserStackCredentials;
70
- /**
71
- * When the BrowserStack run has completed, provides the final results.
72
- */
73
- export interface BrowserStackResults {
74
- readonly passed: boolean;
75
- }
76
- /**
77
- * Runs tests on BrowserStack.
78
- *
79
- * This will:
80
- * - Start a local server including a REST API for serving tests that are expected to report their progress to the
81
- * service.
82
- * - Start the BrowserStack local tunnel.
83
- * - Enqueue workers for each provided browser.
84
- *
85
- * @return Returns a Promise with the test results.
86
- *
87
- * Example:
88
- *
89
- * ```
90
- * void runBrowserStack({
91
- * server: {
92
- * port: 9009,
93
- * staticDir: './dist/test',
94
- * },
95
- * browsers: [
96
- * {
97
- * browser: 'chrome',
98
- * browser_version: 'latest',
99
- * os: 'OS X',
100
- * os_version: 'Monterey',
101
- * },
102
- * {
103
- * browser: 'safari',
104
- * browser_version: 'latest',
105
- * os: 'OS X',
106
- * os_version: 'Monterey',
107
- * },
108
- * ],
109
- * workerCommon: {
110
- * project: 'MyProject',
111
- * },
112
- * }).then((result) => {
113
- * if (!result.passed) process.exit(1)
114
- * })
115
- * ```
116
- */
117
- export declare function runBrowserStack(options: BrowserStackOptions): Promise<BrowserStackResults>;
118
- /**
119
- * Calls {@link runBrowserStack}, exiting the process when settled.
120
- * @param options
121
- */
122
- export declare function runBrowserStackAndExit(options: BrowserStackOptions): void;
123
- //# sourceMappingURL=runBrowserStack.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"runBrowserStack.d.ts","sourceRoot":"","sources":["../../src/browserstack/runBrowserStack.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAErD,OAAO,KAAK,EACR,cAAc,EACd,uBAAuB,EACvB,aAAa,EAChB,MAAM,uBAAuB,CAAA;AAG9B,OAAO,KAAK,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnE,OAAO,KAAK,EAAE,mCAAmC,EAAE,MAAM,gCAAgC,CAAA;AAIzF,OAAO,EAAU,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAMjD,MAAM,WAAW,mBAAoB,SAAQ,mCAAmC;IAC5E;;OAEG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IAExC;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;IAE9B;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EACf,uBAAuB,GACvB,OAAO,CAAC,uBAAuB,CAAC,CAAA;IAEtC;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAA;IAE/C;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,uBAAuB,CAAA;IAE/C;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAA;IAEjC;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAErC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAA;CAC/B;AAED;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACtC,iBAAiB,EACjB,MAAM,cAAc,CACvB,CAAA;AAED,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC;IACjE;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;GAEG;AACH,wBAAgB,6BAA6B,IAAI,uBAAuB,CAavE;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAChC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAsB,eAAe,CACjC,OAAO,EAAE,mBAAmB,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CA2H9B;AAiBD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAazE"}
@@ -1,211 +0,0 @@
1
- /*
2
- * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
- import { config as dotEnvConfig } from 'dotenv';
6
- import express from 'express';
7
- import { startExpressServer } from '../express/startExpressServer';
8
- import { configureExpress } from '../express/serve';
9
- import { BrowserStackAutomateClient } from './browserStackRestApi';
10
- import { startBrowserStackLocal } from './browserStackLocal';
11
- import { BrowserStackWorkerController } from './BrowserStackWorkerController';
12
- import { configureReportingApi } from './configureReporterApi';
13
- import process from 'node:process';
14
- import { logger, LogLevel } from '../util/Logger';
15
- import { ansi, progressBar } from '../util/console';
16
- import { getRootProjectDir } from '../util/getRootProjectDir';
17
- import path from 'node:path';
18
- import crypto from 'node:crypto';
19
- /**
20
- * Attempts to get the BrowserStackCredentials from the environment.
21
- */
22
- export function getEnvBrowserStackCredentials() {
23
- const rootDir = getRootProjectDir();
24
- if (!rootDir)
25
- throw new Error('Could not find root project dir from current working directory.');
26
- dotEnvConfig({
27
- path: path.resolve(rootDir, '.env'),
28
- });
29
- return {
30
- username: process.env.BROWSERSTACK_USERNAME,
31
- key: process.env.BROWSERSTACK_ACCESS_KEY,
32
- };
33
- }
34
- /**
35
- * Runs tests on BrowserStack.
36
- *
37
- * This will:
38
- * - Start a local server including a REST API for serving tests that are expected to report their progress to the
39
- * service.
40
- * - Start the BrowserStack local tunnel.
41
- * - Enqueue workers for each provided browser.
42
- *
43
- * @return Returns a Promise with the test results.
44
- *
45
- * Example:
46
- *
47
- * ```
48
- * void runBrowserStack({
49
- * server: {
50
- * port: 9009,
51
- * staticDir: './dist/test',
52
- * },
53
- * browsers: [
54
- * {
55
- * browser: 'chrome',
56
- * browser_version: 'latest',
57
- * os: 'OS X',
58
- * os_version: 'Monterey',
59
- * },
60
- * {
61
- * browser: 'safari',
62
- * browser_version: 'latest',
63
- * os: 'OS X',
64
- * os_version: 'Monterey',
65
- * },
66
- * ],
67
- * workerCommon: {
68
- * project: 'MyProject',
69
- * },
70
- * }).then((result) => {
71
- * if (!result.passed) process.exit(1)
72
- * })
73
- * ```
74
- */
75
- export async function runBrowserStack(options) {
76
- // Validate options argument
77
- if (!options.browsers.length)
78
- throw new Error('options.browsers is required');
79
- let done;
80
- const donePromise = new Promise((r) => (done = r));
81
- const bsCredentials = (await options.credentials) ?? getEnvBrowserStackCredentials();
82
- if (!bsCredentials.username || !bsCredentials.key)
83
- throw new Error('Missing BrowserStack credentials. May be provided via options.credentials, or the environmental ' +
84
- 'variables BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY. ' +
85
- 'Environmental variables may be set via a .env file.');
86
- // Use the explicitly set stickyProgress value, or default to true if the stdout is a terminal.
87
- const useSticky = options.stickyProgress ?? process.stdout.isTTY;
88
- logger.level = options.logLevel ?? LogLevel.INFO;
89
- const localOptions = {
90
- key: bsCredentials.key,
91
- logFile: './bStackLogs/local.log',
92
- ...options.local,
93
- };
94
- const shutdownLocalTunnel = await startBrowserStackLocal(localOptions);
95
- const app = express();
96
- configureExpress(app, options.server);
97
- const serverHandle = await startExpressServer({ app }, options.server);
98
- const client = new BrowserStackAutomateClient(bsCredentials);
99
- const build = `build-${crypto.randomUUID()}`;
100
- const workerOptions = options.browsers.map((browser) => {
101
- const name = browser.name ?? generateNameForBrowser(browser);
102
- // Url precedence:
103
- let url = browser.url ??
104
- options.workerCommon?.url ??
105
- serverHandle.https?.url ??
106
- serverHandle.http.url;
107
- // Safari and iOS do not route `localhost` through the BrowserStack Local
108
- // tunnel; they must reach the test server via `bs-local.com` (other
109
- // browsers work with either). Without this these workers can never load
110
- // the tests and time out capturing no progress.
111
- if (browser.browser === 'safari' || browser.os === 'ios') {
112
- url = url.replace('//localhost', '//bs-local.com');
113
- }
114
- return {
115
- build,
116
- name,
117
- ...options.workerCommon,
118
- ...browser,
119
- url,
120
- };
121
- });
122
- const workerController = new BrowserStackWorkerController({ client }, workerOptions, options);
123
- configureReportingApi(app, workerController);
124
- const state = workerController.state;
125
- function createProgressMessage() {
126
- let failedStr = `failed: ${state.failed}`;
127
- if (state.failed > 0)
128
- failedStr = ansi.red + failedStr + ansi.resetColor;
129
- return (`${ansi.green}passed: ${state.passed}${ansi.resetColor}, ${failedStr}, running: ${state.running}, pending: ${state.pending}\n` +
130
- progressBar(state.percentComplete));
131
- }
132
- let previousDecile = 0;
133
- workerController.onUpdate = () => {
134
- if (disposed)
135
- return;
136
- const progressStr = createProgressMessage();
137
- if (useSticky)
138
- logger.sticky(progressStr);
139
- else {
140
- const decile = Math.trunc(state.percentComplete * 10);
141
- if (decile !== previousDecile) {
142
- logger.info(progressStr);
143
- previousDecile = decile;
144
- }
145
- }
146
- if (options.stopOnFirstFailure && state.failed)
147
- void shutdown();
148
- if (!state.remaining)
149
- void shutdown();
150
- };
151
- const sigIntHandler = () => {
152
- logger.info('SIGINT signal received.');
153
- void shutdown().then(() => {
154
- process.exit(1);
155
- });
156
- };
157
- process.once('SIGINT', sigIntHandler);
158
- let disposed = false;
159
- async function shutdown() {
160
- if (disposed)
161
- return;
162
- disposed = true;
163
- logger.clearSticky();
164
- logger.info(createProgressMessage());
165
- logger.debug('Shutting down');
166
- process.removeListener('SIGINT', sigIntHandler);
167
- await workerController.terminate();
168
- await serverHandle.close();
169
- await shutdownLocalTunnel();
170
- // Resolve the promise with the final results:
171
- const passed = workerController.allPassed;
172
- if (passed)
173
- logger.info('✅ All tests passed');
174
- done({
175
- passed,
176
- });
177
- }
178
- workerController.start();
179
- return await donePromise;
180
- }
181
- /**
182
- * Creates a session name for the given browser options.
183
- */
184
- function generateNameForBrowser(browser) {
185
- return [
186
- browser.device,
187
- browser.os,
188
- browser.os_version,
189
- browser.browser,
190
- browser.browser_version,
191
- ]
192
- .filter((str) => str)
193
- .join(' ');
194
- }
195
- /**
196
- * Calls {@link runBrowserStack}, exiting the process when settled.
197
- * @param options
198
- */
199
- export function runBrowserStackAndExit(options) {
200
- runBrowserStack(options)
201
- .then((result) => {
202
- if (!result.passed)
203
- process.exit(1);
204
- })
205
- .catch((error) => {
206
- console.error(ansi.red +
207
- String('message' in error ? error.message : error) +
208
- ansi.resetColor);
209
- process.exit(1);
210
- });
211
- }