Browse Source
* First pass at basic browser tests for #1926 * Run tests against dev web server not go server * Bundle the web code into the server before running tests * Move cypress UI tests into its own npm project + add tests * Add additional tests + wire up with cypress dashboard * Limit concurrency of workflow jobs * Temporarily comment out some tests that do not pass in mobile. Will fix later.pull/2306/head
34 changed files with 5672 additions and 338 deletions
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
name: Browser Tests |
||||
|
||||
on: [push, pull_request_target] |
||||
|
||||
jobs: |
||||
cypress-run: |
||||
concurrency: |
||||
group: ${{ github.workflow }}-${{ github.ref }} |
||||
cancel-in-progress: true |
||||
|
||||
runs-on: ubuntu-latest |
||||
steps: |
||||
- name: Checkout |
||||
uses: actions/checkout@v2 |
||||
- uses: actions/setup-go@v3 |
||||
with: |
||||
go-version: '1.18' |
||||
- name: Run Browser tests |
||||
run: cd test/automated/browser && ./run.sh |
||||
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
const { defineConfig } = require('cypress'); |
||||
|
||||
module.exports = defineConfig({ |
||||
projectId: 'wwi3xe', |
||||
e2e: { |
||||
setupNodeEvents(on, config) { |
||||
// implement node event listeners here
|
||||
}, |
||||
}, |
||||
}); |
||||
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
import { setup } from '../../support/setup.js'; |
||||
setup(); |
||||
|
||||
describe(`Basic tests`, () => { |
||||
it('Can visit the page', () => { |
||||
cy.visit('http://localhost:8080/'); |
||||
}); |
||||
|
||||
// Verify the tags show up
|
||||
it('Has correct tags visible', () => { |
||||
cy.contains('#owncast').should('be.visible'); |
||||
cy.contains('#streaming').should('be.visible'); |
||||
}); |
||||
|
||||
// it('Can open notify modal', () => {
|
||||
// cy.contains('Be notified').click();
|
||||
// cy.wait(1500);
|
||||
// cy.get('.ant-modal-close').click();
|
||||
// });
|
||||
|
||||
// it('Can open follow modal', () => {
|
||||
// cy.contains('Follow').click();
|
||||
// cy.wait(1500);
|
||||
// cy.get('.ant-modal-close').click();
|
||||
// });
|
||||
|
||||
it('Can change to Followers tab', () => { |
||||
cy.contains('Followers').click(); |
||||
}); |
||||
|
||||
// Verify content header values
|
||||
it('Has correct content header values', () => { |
||||
cy.get('.header-title').should('have.text', 'Owncast'); |
||||
cy.get('.header-subtitle').should( |
||||
'have.text', |
||||
'Welcome to your new Owncast server! This description can be changed in the admin. Visit https://owncast.online/docs/configuration/ to learn more.' |
||||
); |
||||
}); |
||||
|
||||
it('Has correct global header values', () => { |
||||
cy.get('.global-header-text').should('have.text', 'Owncast'); |
||||
}); |
||||
|
||||
// Offline banner
|
||||
it('Has correct offline banner values', () => { |
||||
cy.contains( |
||||
'This stream is offline. Be notified the next time Owncast goes live.' |
||||
).should('be.visible'); |
||||
}); |
||||
}); |
||||
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
import { setup } from '../../support/setup.js'; |
||||
setup(); |
||||
|
||||
describe(`Offline video embed`, () => { |
||||
it('Can visit the page', () => { |
||||
cy.visit('http://localhost:8080/embed/video'); |
||||
}); |
||||
|
||||
// Offline banner
|
||||
it('Has correct offline banner values', () => { |
||||
cy.contains('This stream is offline. Check back soon!').should( |
||||
'be.visible' |
||||
); |
||||
}); |
||||
}); |
||||
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
import { setup } from '../../support/setup.js'; |
||||
setup(); |
||||
|
||||
describe(`Offline readwrite chat embed`, () => { |
||||
it('Can visit the page', () => { |
||||
cy.visit('http://localhost:8080/embed/chat/readwrite'); |
||||
}); |
||||
}); |
||||
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
import { setup } from '../../support/setup.js'; |
||||
setup(); |
||||
|
||||
describe(`Offline read-only chat embed`, () => { |
||||
it('Can visit the page', () => { |
||||
cy.visit('http://localhost:8080/embed/chat/readwrite'); |
||||
}); |
||||
|
||||
// it('Chat should be visible', () => {
|
||||
// cy.get('#chat-container').should('be.visible');
|
||||
// });
|
||||
}); |
||||
@ -0,0 +1,70 @@
@@ -0,0 +1,70 @@
|
||||
import { setup } from '../../support/setup.js'; |
||||
setup(); |
||||
|
||||
describe(`Live tests`, () => { |
||||
it('Can visit the page', () => { |
||||
cy.visit('http://localhost:8080'); |
||||
}); |
||||
|
||||
it('Should have a play button', () => { |
||||
cy.get('.vjs-big-play-button').should('be.visible'); |
||||
}); |
||||
|
||||
// it('Chat should be visible', () => {
|
||||
// cy.get('#chat-container').should('be.visible');
|
||||
// });
|
||||
|
||||
it('User menu should be visible', () => { |
||||
cy.get('#user-menu').should('be.visible'); |
||||
}); |
||||
|
||||
// it('Chat join message should exist', () => {
|
||||
// cy.contains('joined the chat').should('be.visible');
|
||||
// });
|
||||
|
||||
it('User menu should be visible', () => { |
||||
cy.get('#user-menu').should('be.visible'); |
||||
}); |
||||
|
||||
it('Click on user menu', () => { |
||||
cy.get('#user-menu').click(); |
||||
}); |
||||
|
||||
it('Can toggle chat off', () => { |
||||
cy.contains('Toggle chat').click(); |
||||
}); |
||||
|
||||
it('Chat should not be visible', () => { |
||||
cy.get('#chat-container').should('not.exist'); |
||||
}); |
||||
|
||||
it('Click on user menu', () => { |
||||
cy.get('#user-menu').click(); |
||||
}); |
||||
|
||||
it('Can toggle chat on', () => { |
||||
cy.contains('Toggle chat').click(); |
||||
}); |
||||
|
||||
// it('Chat should be re-visible', () => {
|
||||
// cy.get('#chat-container').should('be.visible');
|
||||
// });
|
||||
|
||||
it('Click on user menu', () => { |
||||
cy.get('#user-menu').click(); |
||||
}); |
||||
|
||||
it('Show change name modal', () => { |
||||
cy.contains('Change name').click(); |
||||
}); |
||||
|
||||
it('Should change name', () => { |
||||
cy.get('#name-change-field').focus(); |
||||
cy.get('#name-change-field').type('{ctrl+a}'); |
||||
cy.get('#name-change-field').type('my-new-name'); |
||||
cy.get('#name-change-submit').click(); |
||||
cy.get('.ant-modal-close-x').click(); |
||||
cy.wait(1500); |
||||
// cy.contains('is now known as').should('be.visible');
|
||||
}); |
||||
}); |
||||
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
import { setup } from '../../support/setup.js'; |
||||
setup(); |
||||
|
||||
describe(`Online video embed`, () => { |
||||
it('Can visit the page', () => { |
||||
cy.visit('http://localhost:8080'); |
||||
}); |
||||
|
||||
it('Should have a play button', () => { |
||||
cy.get('.vjs-big-play-button').should('be.visible'); |
||||
}); |
||||
}); |
||||
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
import { setup } from '../../support/setup.js'; |
||||
setup(); |
||||
|
||||
describe(`Online readwrite chat embed`, () => { |
||||
it('Can visit the page', () => { |
||||
cy.visit('http://localhost:8080/embed/chat/readwrite'); |
||||
}); |
||||
|
||||
// it('Chat should be visible', () => {
|
||||
// cy.get('#chat-container').should('be.visible');
|
||||
// });
|
||||
|
||||
// it('User menu should be visible', () => {
|
||||
// cy.get('#user-menu').should('be.visible');
|
||||
// });
|
||||
|
||||
// it('Chat join message should exist', () => {
|
||||
// cy.contains('joined the chat').should('be.visible');
|
||||
// });
|
||||
|
||||
// it('User menu should be visible', () => {
|
||||
// cy.get('#user-menu').should('be.visible');
|
||||
// });
|
||||
|
||||
// it('Click on user menu', () => {
|
||||
// cy.get('#user-menu').click();
|
||||
// });
|
||||
|
||||
// it('Show change name modal', () => {
|
||||
// cy.contains('Change name').click();
|
||||
// });
|
||||
}); |
||||
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
import { setup } from '../../support/setup.js'; |
||||
setup(); |
||||
|
||||
describe(`Online read-only chat embed`, () => { |
||||
it('Can visit the page', () => { |
||||
cy.visit('http://localhost:8080/embed/chat/readwrite'); |
||||
}); |
||||
|
||||
// it('Chat should be visible', () => {
|
||||
// cy.get('#chat-container').should('be.visible');
|
||||
// });
|
||||
}); |
||||
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
{ |
||||
"name": "Using fixtures to represent data", |
||||
"email": "hello@cypress.io", |
||||
"body": "Fixtures are a great way to mock data for responses to routes" |
||||
} |
||||
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
// ***********************************************************
|
||||
// This example support/e2e.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands' |
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
export function setup() { |
||||
Cypress.on( |
||||
'uncaught:exception', |
||||
(err) => !err.message.includes('ResizeObserver loop limit exceeded') |
||||
); |
||||
} |
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
{ |
||||
"name": "owncast-browser-tests", |
||||
"version": "1.0.0", |
||||
"description": "", |
||||
"main": "index.js", |
||||
"scripts": { |
||||
"test": "echo \"Error: no test specified\" && exit 1" |
||||
}, |
||||
"author": "", |
||||
"license": "ISC", |
||||
"devDependencies": { |
||||
"cypress": "^10.10.0" |
||||
} |
||||
} |
||||
@ -0,0 +1,67 @@
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash |
||||
|
||||
set -o errexit |
||||
set -o nounset |
||||
set -o pipefail |
||||
|
||||
TEMP_DB=$(mktemp) |
||||
BUILD_ID=$((RANDOM % 7200 + 600)) |
||||
|
||||
# Change to the root directory of the repository |
||||
cd "$(git rev-parse --show-toplevel)" |
||||
|
||||
# Bundle the updated web code into the server codebase. |
||||
echo "Bundling web code into server..." |
||||
./build/web/bundleWeb.sh >/dev/null |
||||
|
||||
# Install the web test framework |
||||
echo "Installing test dependencies..." |
||||
pushd test/automated/browser |
||||
npm install --silent >/dev/null |
||||
|
||||
popd |
||||
|
||||
# Download a specific version of ffmpeg |
||||
if [ ! -d "ffmpeg" ]; then |
||||
echo "Downloading ffmpeg..." |
||||
mkdir -p /tmp/ffmpeg |
||||
pushd /tmp/ffmpeg >/dev/null |
||||
curl -sL https://github.com/vot/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-linux-64.zip --output ffmpeg.zip >/dev/null |
||||
unzip -o ffmpeg.zip >/dev/null |
||||
PATH=$PATH:$(pwd) |
||||
popd >/dev/null |
||||
fi |
||||
|
||||
# Build and run owncast from source |
||||
echo "Building owncast..." |
||||
go build -o owncast main.go |
||||
echo "Running owncast..." |
||||
./owncast -database $TEMP_DB & |
||||
SERVER_PID=$! |
||||
|
||||
pushd test/automated/browser |
||||
|
||||
# Run cypress browser tests for desktop |
||||
npx cypress run --group "desktop-offline" --ci-build-id $BUILD_ID --tag "desktop,offline" --record --key e9c8b547-7a8f-452d-8c53-fd7531491e3b --spec "cypress/e2e/offline/*.cy.js" |
||||
# Run cypress browser tests for mobile |
||||
npx cypress run --group "mobile-offline" --ci-build-id $BUILD_ID --tag "mobile,offline" --record --key e9c8b547-7a8f-452d-8c53-fd7531491e3b --spec "cypress/e2e/offline/*.cy.js" --config viewportWidth=375,viewportHeight=667 |
||||
|
||||
# Start streaming the test file over RTMP to |
||||
# the local owncast instance. |
||||
echo "Waiting for stream to start..." |
||||
ffmpeg -hide_banner -loglevel panic -stream_loop -1 -re -i ../test.mp4 -vcodec libx264 -profile:v main -sc_threshold 0 -b:v 1300k -acodec copy -f flv rtmp://127.0.0.1/live/abc123 & |
||||
STREAMING_CLIENT=$! |
||||
|
||||
function finish { |
||||
echo "Cleaning up..." |
||||
rm $TEMP_DB |
||||
kill $SERVER_PID $STREAMING_CLIENT |
||||
} |
||||
trap finish EXIT SIGHUP SIGINT SIGTERM SIGQUIT SIGABRT SIGTERM |
||||
|
||||
sleep 20 |
||||
|
||||
# Run cypress browser tests for desktop |
||||
npx cypress run --group "desktop-online" --ci-build-id $BUILD_ID --tag "desktop,online" --record --key e9c8b547-7a8f-452d-8c53-fd7531491e3b --spec "cypress/e2e/online/*.cy.js" |
||||
# Run cypress browser tests for mobile |
||||
npx cypress run --group "mobile-online" --ci-build-id $BUILD_ID --tag "mobile,online" --record --key e9c8b547-7a8f-452d-8c53-fd7531491e3b --spec "cypress/e2e/online/*.cy.js" --config viewportWidth=375,viewportHeight=667 |
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue