Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

# Unreleased

## Changed
- Port binding behaviour now starts from 0 to avoid race conditions. #TINY-13630
- Compiled tests moved to custom scratch folder. #TINY-13630

# 15.1.1 - 2025-12-19

## Unreleased
Expand Down
67 changes: 31 additions & 36 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
standardProperties()

timestamps {
tinyPods.node(
tinyPods.nodeBrowser(
tag: '20',
resourceRequestMemory: '2Gi',
resourceLimitMemory: '2Gi'
resourceRequestMemory: '4Gi',
resourceLimitMemory: '4Gi'
) {
stage("clean") {
exec('yarn clean')
Expand All @@ -26,43 +26,38 @@ timestamps {
stage("test") {
exec('yarn test')
}
}

// Testing
stage("bedrock testing") {
bedrockRemoteBrowsers(
testContainer: [
resourceRequestMemory: '2Gi',
resourceLimitMemory: '2Gi',
],
platforms: [
[ browser: 'chrome', provider: 'aws', buckets: 2 ],
[ browser: 'firefox', provider: 'aws', buckets: 2 ],
[ browser: 'edge', provider: 'lambdatest', buckets: 1 ],
[ browser: 'chrome', provider: 'lambdatest', os: 'macOS Sonoma', buckets: 1 ],
[ browser: 'firefox', provider: 'lambdatest', os: 'macOS Sonoma', buckets: 1 ],
[ browser: 'safari', provider: 'lambdatest', os: 'macOS Sonoma', buckets: 1 ],
],
prepareTests: {
yarnInstall()
sh 'yarn build'
},
def platforms = [
[ browser: 'chrome', provider: 'aws', buckets: 2 ],
[ browser: 'firefox', provider: 'aws', buckets: 2 ],
[ browser: 'edge', provider: 'lambdatest' ],
[ browser: 'chrome', provider: 'lambdatest', os: 'macOS Sonoma' ],
[ browser: 'firefox', provider: 'lambdatest', os: 'macOS Sonoma' ],
[ browser: 'safari', provider: 'lambdatest', os: 'macOS Sonoma' ],
[ browser: 'chrome', provider: 'headless' ]
]

def cleanBranchName = (env.BRANCH_NAME ?: "").split('/').last()
def testPrefix = "Bedrock_${cleanBranchName}-b${env.BUILD_NUMBER}"

bedrockLocalBrowsers(
testDirs: [ 'modules/sample/src/test/ts/**/pass' ],
custom: '--config modules/sample/tsconfig.json --customRoutes modules/sample/routes.json'
custom: '--config modules/sample/tsconfig.json --customRoutes modules/sample/routes.json',
platforms: platforms,
prefix: testPrefix
)
}

// Publish
if (isReleaseBranch()) {
stage("publish") {
tinyPods.node() {
yarnInstall()
sh 'yarn build'
tinyNpm.withNpmPublishCredentials {
// We need to tell git to ignore the changes to .npmrc when publishing
exec('git update-index --assume-unchanged .npmrc')
// Re-evaluate whether we still need the `--no-verify-access` flag after upgrading Lerna (TINY-13539)
exec('yarn lerna publish from-package --yes --no-git-reset --ignore @ephox/bedrock-sample --no-verify-access')
if (isReleaseBranch()) {
stage("publish") {
tinyPods.node() {
yarnInstall()
sh 'yarn build'
tinyNpm.withNpmPublishCredentials {
// We need to tell git to ignore the changes to .npmrc when publishing
exec('git update-index --assume-unchanged .npmrc')
// Re-evaluate whether we still need the `--no-verify-access` flag after upgrading Lerna (TINY-13539)
exec('yarn lerna publish from-package --yes --no-git-reset --ignore @ephox/bedrock-sample --no-verify-access')
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions modules/sample/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"author": "Tiny Technologies Inc",
"license": "Apache-2.0",
"scripts": {
"bedrock": "node ../server/bin/bedrock.js",
"bedrock-auto": "node ../server/bin/bedrock-auto.js",
"bedrock": "node ../server/bin/bedrock.cjs",
"bedrock-auto": "node ../server/bin/bedrock-auto.cjs",
"test-samples-pass": "bedrock-auto -b chrome-headless --config tsconfig.json --customRoutes routes.json -d src/test/ts/**/pass",
"test-samples-only": "bedrock-auto -b chrome-headless --config tsconfig.json -d src/test/ts/**/only",
"test-samples-pass-js": "bedrock-auto -b chrome-headless -d src/test/js/**/pass",
Expand Down
14 changes: 14 additions & 0 deletions modules/server/bin/bedrock-auto.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env node

const BedrockCli = require("../lib/main/ts/BedrockCli");
const BedrockAuto = require("../lib/main/ts/BedrockAuto");

(async () => {
await BedrockCli.run(BedrockAuto, {
current: process.cwd(),
bin: __dirname,
});
})().catch((err) => {
console.error(err);
process.exit(1);
});
9 changes: 0 additions & 9 deletions modules/server/bin/bedrock-auto.js

This file was deleted.

14 changes: 14 additions & 0 deletions modules/server/bin/bedrock.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env node

const BedrockCli = require("../lib/main/ts/BedrockCli");
const BedrockManual = require("../lib/main/ts/BedrockManual");

(async () => {
await BedrockCli.run(BedrockManual, {
current: process.cwd(),
bin: __dirname,
});
})().catch((err) => {
console.error(err);
process.exit(1);
});
9 changes: 0 additions & 9 deletions modules/server/bin/bedrock.js

This file was deleted.

4 changes: 2 additions & 2 deletions modules/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"author": "Tiny Technologies Inc",
"license": "Apache-2.0",
"bin": {
"bedrock-auto": "./bin/bedrock-auto.js",
"bedrock": "./bin/bedrock.js"
"bedrock-auto": "./bin/bedrock-auto.cjs",
"bedrock": "./bin/bedrock.cjs"
},
"scripts": {
"prepublishOnly": "tsc -b",
Expand Down
128 changes: 70 additions & 58 deletions modules/server/src/main/ts/BedrockAuto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,58 @@ import { BedrockAutoSettings } from './bedrock/core/Settings';
import { ExitCodes } from './bedrock/util/ExitCodes';
import * as ConsoleReporter from './bedrock/core/ConsoleReporter';
import * as SettingsResolver from './bedrock/core/SettingsResolver';
import * as portfinder from 'portfinder';
import { format } from 'node:util';
import { Browser } from 'webdriverio';
import { defer } from './bedrock/util/Waiter';

export const go = (bedrockAutoSettings: BedrockAutoSettings): void => {
async function makeWebDriver(settings: BedrockAutoSettings, servicePort: number, shutdownServices: ((immediate?: boolean) => Promise<void>)[], browserName: string, isHeadless: boolean) {
// Remote settings
const remoteWebdriver = settings.remote;
const sishDomain = settings.sishDomain;
const username = settings.username ?? process.env.LT_USERNAME;
const accesskey = settings.accesskey ?? process.env.LT_ACCESS_KEY;
const tunnelCredentials = {
user: username,
key: accesskey
};

const tunnel = await Tunnel.prepareConnection(servicePort, remoteWebdriver, sishDomain, tunnelCredentials);
shutdownServices.push(tunnel.shutdown);
const location = tunnel.url.href;

console.log(`Creating ${ remoteWebdriver ?? 'local' } webdriver...`);
if (remoteWebdriver == 'aws') {
console.log('INFO: Webdriver creation waits for device farm session to activate. Takes 30-45s.');
}

const driver = await Driver.create({
browser: browserName,
basedir: settings.basedir,
headless: isHeadless,
debuggingPort: settings.debuggingPort,
useSandboxForHeadless: settings.useSandboxForHeadless,
extraBrowserCapabilities: settings.extraBrowserCapabilities,
verbose: settings.verbose,
wipeBrowserCache: settings.wipeBrowserCache,
remoteWebdriver,
webdriverPort: settings.webdriverPort,
useSelenium: settings.useSelenium,
username,
accesskey,
devicefarmRegion: settings.devicefarmRegion,
deviceFarmArn: settings.devicefarmArn,
browserVersion: settings.browserVersion,
platformName: settings.platformName,
tunnel,
name: settings.name ? settings.name : 'bedrock-auto'
});
shutdownServices.push(driver.shutdown);

const webdriver = driver.webdriver;
return { location, webdriver };
}

export const go = async (bedrockAutoSettings: BedrockAutoSettings): Promise<void> => {
console.log('bedrock-auto ' + Version.get() + ' starting...');

const settings = SettingsResolver.resolveAndLog(bedrockAutoSettings);
Expand All @@ -24,72 +72,36 @@ export const go = (bedrockAutoSettings: BedrockAutoSettings): void => {
const isPhantom = browserName === 'phantomjs';
const isHeadless = settings.browser.endsWith('-headless') || isPhantom;
const basePage = 'src/resources/html/' + (isPhantom ? 'bedrock-phantom.html' : 'bedrock.html');
// Remote settings
const remoteWebdriver = settings.remote;
const sishDomain = settings.sishDomain;
const username = settings.username ?? process.env.LT_USERNAME;
const accesskey = settings.accesskey ?? process.env.LT_ACCESS_KEY;

const routes = RunnerRoutes.generate('auto', settings.projectdir, settings.basedir, settings.config, settings.bundler, settings.testfiles, settings.chunk, settings.retries, settings.singleTimeout, settings.stopOnFailure, basePage, settings.coverage, settings.polyfills);

const shutdownServices: ((immediate?: boolean) => Promise<void>)[] = [];
const shutdown = (services: ((immediate?: boolean) => Promise<void>)[]) => (immediate?: boolean) => Promise.allSettled(services.map((fn) => fn(immediate)));

routes.then(async (runner) => {

// LambdaTest Tunnel must know dev server port, but tunnel must be created before dev server.
const servicePort = await portfinder.getPortPromise({
port: 8000,
stopPort: 20000
});

const tunnelCredentials = {
user: username,
key: accesskey
};
try {

const tunnel = await Tunnel.prepareConnection(servicePort, remoteWebdriver, sishDomain, tunnelCredentials);
shutdownServices.push(tunnel.shutdown);
const location = tunnel.url.href;
const driverDeferred = defer<Attempt<unknown, Browser>>();

console.log(`Creating ${remoteWebdriver ?? 'local'} webdriver...`);
if (remoteWebdriver == 'aws') {
console.log('INFO: Webdriver creation waits for device farm session to activate. Takes 30-45s.');
}
const scratchDir = settings.name ? `scratch_${settings.name}` : `bedrock`;

const driver = await Driver.create({
browser: browserName,
basedir: settings.basedir,
headless: isHeadless,
debuggingPort: settings.debuggingPort,
useSandboxForHeadless: settings.useSandboxForHeadless,
extraBrowserCapabilities: settings.extraBrowserCapabilities,
verbose: settings.verbose,
wipeBrowserCache: settings.wipeBrowserCache,
remoteWebdriver,
webdriverPort: settings.webdriverPort,
useSelenium: settings.useSelenium,
username,
accesskey,
devicefarmRegion: settings.devicefarmRegion,
deviceFarmArn: settings.devicefarmArn,
browserVersion: settings.browserVersion,
platformName: settings.platformName,
tunnel,
name: settings.name ? settings.name : 'bedrock-auto'
});
const routesPromise = RunnerRoutes.generate('auto', settings.projectdir, settings.basedir, scratchDir, settings.config, settings.bundler, settings.testfiles, settings.chunk, settings.retries, settings.singleTimeout, settings.stopOnFailure, basePage, settings.coverage, settings.polyfills);

const webdriver = driver.webdriver;
console.log('Started webdriver session: ', webdriver.sessionId);
const service = await Serve.start({
...settings,
driver: Attempt.passed(webdriver),
driver: driverDeferred.promise,
master,
runner,
runner: routesPromise,
stickyFirstSession: true,
port: servicePort
});
shutdownServices.push(service.shutdown, driver.shutdown);
const driverPromise = makeWebDriver(settings, service.port, shutdownServices, browserName, isHeadless);
driverPromise.then(({ webdriver }) => {
driverDeferred.resolve(Attempt.passed(webdriver));
}).catch((e) => {
driverDeferred.reject(Attempt.failed(e));
});

shutdownServices.push(service.shutdown);

const { location, webdriver } = await driverPromise;
console.log('Started webdriver session: ', webdriver.sessionId);

const cancelEverything = Lifecycle.cancel(webdriver, shutdown(shutdownServices), settings.gruntDone);
process.on('SIGINT', cancelEverything);
Expand Down Expand Up @@ -119,13 +131,13 @@ export const go = (bedrockAutoSettings: BedrockAutoSettings): void => {
} catch (e) {
return Lifecycle.error(e as any, webdriver, shutdown(shutdownServices), settings.gruntDone, settings.delayExit);
}
}).catch(async (err) => {
} catch(err) {
// Chalk does not use a formatter. Using node's built-in to expand Objects, etc.
console.error(chalk.red('Error creating webdriver', format(err)));
// Shutdown tunnels in case webdriver fails
await shutdown(shutdownServices)(true);
Lifecycle.exit(settings.gruntDone, ExitCodes.failures.unexpected);
});
return Lifecycle.exit(settings.gruntDone, ExitCodes.failures.unexpected);
}
};

export const mode = 'forAuto';
8 changes: 4 additions & 4 deletions modules/server/src/main/ts/BedrockCli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ import * as Util from 'util';
Util.inspect.defaultOptions.depth = null;

type Program = {
go: <T extends BedrockSettings>(settings: T, directories: { current: string; bin: string }) => void;
go: <T extends BedrockSettings>(settings: T, directories: { current: string; bin: string }) => Promise<void>;
mode: 'forAuto' | 'forManual';
}

export const run = (program: Program, directories: { current: string; bin: string }): void => {
export const run = async (program: Program, directories: { current: string; bin: string }): Promise<void> => {
if (Clis[program.mode] === undefined) {
throw new Error('Bedrock mode not known: ' + program.mode);
}

const maybeSettings: Attempt<CliError, BedrockSettings> = Clis[program.mode](directories);
Attempt.cata(maybeSettings, Clis.logAndExit, (settings) => {
program.go(settings, directories);
await Attempt.cata(maybeSettings, Clis.logAndExit, async (settings) => {
await program.go(settings, directories);
});
};
Loading
Loading