First Test Run on Sauce Labs
parent
a0c57b9c11
commit
5aa8d9ca5f
|
@ -0,0 +1,117 @@
|
|||
# Leave the powered by Sauce Labs bit in as this means we get additional concurrency
|
||||
name: "Frontend tests powered by Sauce Labs"
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
withoutplugins:
|
||||
name: without plugins
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Generate Sauce Labs strings
|
||||
id: sauce_strings
|
||||
run: |
|
||||
printf %s\\n '::set-output name=name::${{ github.workflow }} - ${{ github.job }}'
|
||||
printf %s\\n '::set-output name=tunnel_id::${{ github.run_id }}-${{ github.run_number }}-${{ github.job }}'
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 12
|
||||
|
||||
- name: Install all dependencies and symlink for ep_etherpad-lite
|
||||
run: src/bin/installDeps.sh
|
||||
|
||||
- name: export GIT_HASH to env
|
||||
id: environment
|
||||
run: echo "::set-output name=sha_short::$(git rev-parse --short ${{ github.sha }})"
|
||||
|
||||
- name: Create settings.json
|
||||
run: cp settings.json.template settings.json
|
||||
|
||||
- name: Disable import/export rate limiting
|
||||
run: |
|
||||
sed -e '/^ *"importExportRateLimiting":/,/^ *\}/ s/"max":.*/"max": 0/' -i settings.json
|
||||
|
||||
- uses: saucelabs/sauce-connect-action@v1
|
||||
with:
|
||||
username: ${{ secrets.SAUCE_USERNAME }}
|
||||
accessKey: ${{ secrets.SAUCE_ACCESS_KEY }}
|
||||
tunnelIdentifier: ${{ steps.sauce_strings.outputs.tunnel_id }}
|
||||
|
||||
- name: Run the frontend tests
|
||||
shell: bash
|
||||
env:
|
||||
SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
|
||||
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
|
||||
SAUCE_NAME: ${{ steps.sauce_strings.outputs.name }}
|
||||
TRAVIS_JOB_NUMBER: ${{ steps.sauce_strings.outputs.tunnel_id }}
|
||||
GIT_HASH: ${{ steps.environment.outputs.sha_short }}
|
||||
run: |
|
||||
src/tests/frontend/travis/runner.sh
|
||||
|
||||
withplugins:
|
||||
name: with plugins
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Generate Sauce Labs strings
|
||||
id: sauce_strings
|
||||
run: |
|
||||
printf %s\\n '::set-output name=name::${{ github.workflow }} - ${{ github.job }}'
|
||||
printf %s\\n '::set-output name=tunnel_id::${{ github.run_id }}-${{ github.run_number }}-${{ github.job }}'
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 12
|
||||
|
||||
- name: Install Etherpad plugins
|
||||
# The --legacy-peer-deps flag is required to work around a bug in npm v7:
|
||||
# https://github.com/npm/cli/issues/2199
|
||||
run: >
|
||||
npm install --no-save --legacy-peer-deps
|
||||
# include any plugins here..
|
||||
|
||||
# This must be run after installing the plugins, otherwise npm will try to
|
||||
# hoist common dependencies by removing them from src/node_modules and
|
||||
# installing them in the top-level node_modules. As of v6.14.10, npm's hoist
|
||||
# logic appears to be buggy, because it sometimes removes dependencies from
|
||||
# src/node_modules but fails to add them to the top-level node_modules. Even
|
||||
# if npm correctly hoists the dependencies, the hoisting seems to confuse
|
||||
# tools such as `npm outdated`, `npm update`, and some ESLint rules.
|
||||
- name: Install all dependencies and symlink for ep_etherpad-lite
|
||||
run: src/bin/installDeps.sh
|
||||
|
||||
- name: export GIT_HASH to env
|
||||
id: environment
|
||||
run: echo "::set-output name=sha_short::$(git rev-parse --short ${{ github.sha }})"
|
||||
|
||||
- name: Create settings.json
|
||||
run: cp settings.json.template settings.json
|
||||
|
||||
- name: Disable import/export rate limiting
|
||||
run: |
|
||||
sed -e '/^ *"importExportRateLimiting":/,/^ *\}/ s/"max":.*/"max": 0/' -i settings.json
|
||||
|
||||
- uses: saucelabs/sauce-connect-action@v1
|
||||
with:
|
||||
username: ${{ secrets.SAUCE_USERNAME }}
|
||||
accessKey: ${{ secrets.SAUCE_ACCESS_KEY }}
|
||||
tunnelIdentifier: ${{ steps.sauce_strings.outputs.tunnel_id }}
|
||||
|
||||
- name: Run the frontend tests
|
||||
shell: bash
|
||||
env:
|
||||
SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
|
||||
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
|
||||
SAUCE_NAME: ${{ steps.sauce_strings.outputs.name }}
|
||||
TRAVIS_JOB_NUMBER: ${{ steps.sauce_strings.outputs.tunnel_id }}
|
||||
GIT_HASH: ${{ steps.environment.outputs.sha_short }}
|
||||
run: |
|
||||
src/tests/frontend/travis/collabrunner.sh
|
|
@ -1,91 +1,32 @@
|
|||
'use strict';
|
||||
|
||||
// Test for https://github.com/ether/etherpad-lite/issues/1763
|
||||
|
||||
// This test fails in Opera, IE and Safari
|
||||
// Opera fails due to a weird way of handling the order of execution,
|
||||
// yet actual performance seems fine
|
||||
// Safari fails due the delay being too great yet the actual performance seems fine
|
||||
// Firefox might panic that the script is taking too long so will fail
|
||||
// IE will fail due to running out of memory as it can't fit 2M chars in memory.
|
||||
|
||||
// Just FYI Google Docs crashes on large docs whilst trying to Save,
|
||||
// it's likely the limitations we are
|
||||
// experiencing are more to do with browser limitations than improper implementation.
|
||||
// A ueber fix for this would be to have a separate lower cpu priority
|
||||
// thread that handles operations that aren't
|
||||
// visible to the user.
|
||||
|
||||
// Adapted from John McLear's original test case.
|
||||
|
||||
xdescribe('Responsiveness of Editor', function () {
|
||||
describe('Responsiveness of Editor', function () {
|
||||
// create a new pad before each test run
|
||||
beforeEach(function (cb) {
|
||||
helper.newPad(cb);
|
||||
helper.newPad(cb, 'TEST_PAD_collab');
|
||||
this.timeout(6000);
|
||||
});
|
||||
// JM commented out on 8th Sep 2020 for a release, after release this needs uncommenting
|
||||
// And the test needs to be fixed to work in Firefox 52 on Windows 7.
|
||||
// I am not sure why it fails on this specific platform
|
||||
// The errors show this.timeout... then crash the browser but
|
||||
// I am sure something is actually causing the stack trace and
|
||||
// I just need to narrow down what, offers to help accepted.
|
||||
it('Fast response to keypress in pad with large amount of contents', function (done) {
|
||||
// skip on Windows Firefox 52.0
|
||||
if (window.bowser &&
|
||||
window.bowser.windows && window.bowser.firefox && window.bowser.version === '52.0') {
|
||||
this.skip();
|
||||
|
||||
it('Fast response to keypress in pad with large amount of contents', async function () {
|
||||
if (top.window.location.search.indexOf('&collab=true') === -1) this.skip();
|
||||
const numberOfEdits = 10; // TODO; edit to 1500 or so
|
||||
|
||||
// wait a minute for everyone to connect
|
||||
await helper.waitForPromise(
|
||||
() => parseInt(helper.padChrome$('#online_count').text()) === 4, 60000);
|
||||
|
||||
// send random characters to last div
|
||||
let i = 0;
|
||||
while (i < numberOfEdits) {
|
||||
// Put the text contents into the pad
|
||||
// intentional white space at end of string
|
||||
helper.padInner$('div').last().sendkeys(`${Math.random().toString(36).substring(7)} `);
|
||||
// wait 1500 milliseconds to simulate 40wpm
|
||||
await wait(1500);
|
||||
i++;
|
||||
}
|
||||
const inner$ = helper.padInner$;
|
||||
const chars = '0000000000'; // row of placeholder chars
|
||||
const amount = 200000; // number of blocks of chars we will insert
|
||||
const length = (amount * (chars.length) + 1); // include a counter for each space
|
||||
let text = ''; // the text we're gonna insert
|
||||
this.timeout(amount * 150); // Changed from 100 to 150 to allow Mac OSX Safari to be slow.
|
||||
|
||||
// get keys to send
|
||||
const keyMultiplier = 10; // multiplier * 10 == total number of key events
|
||||
let keysToSend = '';
|
||||
for (let i = 0; i <= keyMultiplier; i++) {
|
||||
keysToSend += chars;
|
||||
}
|
||||
|
||||
const textElement = inner$('div');
|
||||
textElement.sendkeys('{selectall}'); // select all
|
||||
textElement.sendkeys('{del}'); // clear the pad text
|
||||
|
||||
for (let i = 0; i <= amount; i++) {
|
||||
text = `${text + chars} `; // add the chars and space to the text contents
|
||||
}
|
||||
inner$('div').first().text(text); // Put the text contents into the pad
|
||||
|
||||
// Wait for the new contents to be on the pad
|
||||
helper.waitFor(() => inner$('div').text().length > length).done(() => {
|
||||
// has the text changed?
|
||||
expect(inner$('div').text().length).to.be.greaterThan(length);
|
||||
const start = Date.now(); // get the start time
|
||||
|
||||
// send some new text to the screen (ensure all 3 key events are sent)
|
||||
const el = inner$('div').first();
|
||||
for (let i = 0; i < keysToSend.length; ++i) {
|
||||
const x = keysToSend.charCodeAt(i);
|
||||
['keyup', 'keypress', 'keydown'].forEach((type) => {
|
||||
const e = new $.Event(type);
|
||||
e.keyCode = x;
|
||||
el.trigger(e);
|
||||
});
|
||||
}
|
||||
|
||||
helper.waitFor(() => { // Wait for the ability to process
|
||||
const el = inner$('body');
|
||||
if (el[0].textContent.length > amount) return true;
|
||||
}).done(() => {
|
||||
const end = Date.now(); // get the current time
|
||||
const delay = end - start; // get the delay as the current time minus the start time
|
||||
|
||||
expect(delay).to.be.below(600);
|
||||
done();
|
||||
}, 5000);
|
||||
}, 10000);
|
||||
});
|
||||
});
|
||||
|
||||
const wait = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
#!/bin/sh
|
||||
|
||||
pecho() { printf %s\\n "$*"; }
|
||||
log() { pecho "$@"; }
|
||||
error() { log "ERROR: $@" >&2; }
|
||||
fatal() { error "$@"; exit 1; }
|
||||
try() { "$@" || fatal "'$@' failed"; }
|
||||
|
||||
# Move to the Etherpad base directory.
|
||||
MY_DIR=$(try cd "${0%/*}" && try pwd -P) || exit 1
|
||||
try cd "${MY_DIR}/../../../.."
|
||||
|
||||
log "Assuming src/bin/installDeps.sh has already been run"
|
||||
node src/node/server.js --experimental-worker "${@}" &
|
||||
ep_pid=$!
|
||||
|
||||
log "Waiting for Etherpad to accept connections (http://localhost:9001)..."
|
||||
connected=false
|
||||
can_connect() {
|
||||
curl -sSfo /dev/null http://localhost:9001/ || return 1
|
||||
connected=true
|
||||
}
|
||||
now() { date +%s; }
|
||||
start=$(now)
|
||||
while [ $(($(now) - $start)) -le 15 ] && ! can_connect; do
|
||||
sleep 1
|
||||
done
|
||||
[ "$connected" = true ] \
|
||||
|| fatal "Timed out waiting for Etherpad to accept connections"
|
||||
log "Successfully connected to Etherpad on http://localhost:9001"
|
||||
|
||||
# start the remote runner
|
||||
try cd "${MY_DIR}"
|
||||
log "Starting the remote runner..."
|
||||
node remote_runner.js collab
|
||||
exit_code=$?
|
||||
|
||||
kill "$ep_pid" && wait "$ep_pid"
|
||||
log "Done."
|
||||
exit "$exit_code"
|
|
@ -11,6 +11,7 @@ const config = {
|
|||
};
|
||||
|
||||
const isAdminRunner = process.argv[2] === 'admin';
|
||||
const isCollabRunner = process.argv[2] === 'collab';
|
||||
|
||||
let allTestsPassed = true;
|
||||
// overwrite the default exit code
|
||||
|
@ -37,8 +38,14 @@ const sauceTestWorker = async.queue((testSettings, callback) => {
|
|||
// don't know how to print them into output of the tests
|
||||
testSettings.extendedDebugging = true;
|
||||
testSettings.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||
let testURL;
|
||||
if (isCollabRunner) {
|
||||
testURL = 'http://localhost:9001/tests/frontend/index.html?grep=responsiveness%5C.js&collab=true';
|
||||
} else {
|
||||
testURL = 'http://localhost:9001/tests/frontend/';
|
||||
}
|
||||
|
||||
browser.init(testSettings).get('http://localhost:9001/tests/frontend/', () => {
|
||||
browser.init(testSettings).get(testURL, () => {
|
||||
const url = `https://saucelabs.com/jobs/${browser.sessionID}`;
|
||||
console.log(`Remote sauce test '${name}' started! ${url}`);
|
||||
|
||||
|
|
Loading…
Reference in New Issue