Skip to content

Instantly share code, notes, and snippets.

@mciastek
Last active May 21, 2020 13:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mciastek/fd332185edb44336b4d3fcab9b9cda75 to your computer and use it in GitHub Desktop.
Save mciastek/fd332185edb44336b4d3fcab9b9cda75 to your computer and use it in GitHub Desktop.
Set of files for running TestCafe with BrowserStack in Docker
import yargs from 'yargs';
import isDocker from 'is-docker';
const argvConfig = yargs.strict().options({
watch: {
alias: 'w',
describe: 'Runs tests in live mode (only for local browsers)',
type: 'boolean',
},
path: {
alias: 'p',
describe: 'Path or glob pointing to test files',
default: 'spec/**/*.ts',
type: 'string',
},
browser: {
alias: 'b',
describe: 'Runs test for specific browser',
type: 'string',
},
});
const argv = argvConfig.parse();
const runsInContainer = isDocker();
// In Docker we can use only headless browsers
const firefox = (runsInContainer) ? 'firefox:headless' : 'firefox';
const chrome = (runsInContainer) ? 'chromium:headless' : 'chrome';
const localBrowsers = [firefox, chrome];
const remoteBrowsers = ['browserstack:ie@11.0:Windows 10'];
const browsers = (() => {
// Passed browser takes precedence over others
if (argv.browser) {
return argv.browser;
}
// We use only local browsers in watch mode
if (argv.watch) {
return localBrowsers;
}
return [...localBrowsers, ...remoteBrowsers];
})();
// Missing exported TestCafe type from 'testcafe' 😢
// @ts-ignore
const getRunner = (testcafe) => (
(argv.watch) ? testcafe.createLiveModeRunner.bind(testcafe) : testcafe.createRunner.bind(testcafe)
);
const runTests = async (browsers: string[] | string) => {
const testcafe = await createTestCafe('localhost', 1337, 1338);
const runnerFactory = getRunner(testcafe);
const runner = runnerFactory();
await runner.src([argv.path])
.browsers(browsers)
.run(RUNNER_OPTIONS);
return testcafe.close();
};
runTests(browsers); // run our tests!
version: '3.7'
services:
frontend:
# your config for frontend service
frontend-e2e:
build:
context: ./frontend-e2e
command: ["yarn", "test"]
volumes:
- ../frontend-e2e:/app
ports:
- "1337:1337"
- "1338:1338"
links:
- frontend
FROM alpine:edge
RUN addgroup -g 1000 node \
&& adduser -u 1000 -G node -s /bin/sh -D node
RUN mkdir -p /app
# Install required dependencies (with Chromium and Firefox)
RUN apk update && \
echo "http://dl-cdn.alpinelinux.org/alpine/edge/main" >> /etc/apk/repositories && \
echo "http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories && \
echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
apk add --no-cache --purge -u \
nodejs nodejs-npm yarn \
chromium firefox \
xwininfo xvfb dbus eudev ttf-freefont fluxbox procps xvfb-run \
nss freetype freetype-dev harfbuzz \
ca-certificates wget
# Get glibc
RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
RUN wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.29-r0/glibc-2.29-r0.apk
RUN apk add glibc-2.29-r0.apk
# Get glibc-bin and glibc-i18n (required by BrowserStack Local)
RUN wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.29-r0/glibc-bin-2.29-r0.apk
RUN wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.29-r0/glibc-i18n-2.29-r0.apk
RUN apk --update add glibc-bin-2.29-r0.apk glibc-i18n-2.29-r0.apk
RUN /usr/glibc-compat/bin/localedef -i en_US -f UTF-8 en_US.UTF-8
# Required by Chromium and Firefox
RUN apk add libstdc++
# Get BrowserStack Local
RUN wget https://www.browserstack.com/browserstack-local/BrowserStackLocal-linux-x64.zip \
&& unzip BrowserStackLocal-linux-x64.zip \
&& chmod +x BrowserStackLocal \
&& mv BrowserStackLocal /usr/local/bin \
&& rm BrowserStackLocal-linux-x64.zip
ENV CHROME_BIN=/usr/bin/chromium-browser \
CHROME_PATH=/usr/lib/chromium/
# Copy install-deps script that installs Node.js dependecies
# Practically `yarn install` command
COPY install-deps /usr/local/bin/
RUN chmod +x /usr/local/bin/install-deps
# Clear cache
RUN rm -rf /var/cache/apk/*
WORKDIR /app
# Switching to non-root user
USER node
# Required for TestCafe
EXPOSE 1337 1338
# Install Node.js dependecies
ENTRYPOINT [ "install-deps" ]
CMD xvfb-run --server-num=99 --server-args='-ac -screen 0 1024x768x16' yarn test
#!/bin/sh
echo "Installing dependencies..."
yarn install && yarn cache clean
exec "$@"
{
"name": "frontend-e2e",
"version": "1.0.0",
"scripts": {
"test": "NODE_ENV=development ts-node lib",
"test:prod": "NODE_ENV=production ts-node lib"
},
"dependencies": {
"babel-eslint": "^10.0.2",
"chalk": "^2.4.2",
"dotenv": "^8.0.0",
"is-docker": "^2.0.0",
"testcafe": "^1.3.3",
"testcafe-browser-provider-browserstack": "^1.9.0",
"ts-node": "^8.3.0",
"yargs": "^14.0.0"
},
"devDependencies": {
"@types/yargs": "^13.0.2",
"eslint-plugin-import": "^2.18.2",
"tslint": "^5.20.0",
"tslint-eslint-rules": "^5.4.0",
"typescript": "^3.6.3"
}
}
import { Selector } from 'testcafe';
fixture('Kyero Page')
.page('https://www.kyero.com/');
test('Has page title', async (t) => {
const title = Selector('title');
await t.expect(title.textContent).eql('Property for sale and rent in Spain - Kyero.com');
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment