From a3aee3603f6baf02998d607ee3a1f66d994aeae9 Mon Sep 17 00:00:00 2001 From: James Read Date: Tue, 23 Apr 2024 21:54:54 +0100 Subject: [PATCH] More screenshots link (#289) * More screenshots link * bugfix: wip * cicd: Test flakey tests * cicd: more tests * cicd: more tests * cicd: Try a 10s timeout * cicd: Better debugging of process start / stop * cicd: Better debugging of process start / stop * cicd: Possibly unflaky tests --- README.md | 1 + integration-tests/Makefile | 8 ++- integration-tests/lib/elements.js | 15 ++++++ integration-tests/runner.mjs | 57 +++++++++++++-------- integration-tests/test/entities.js | 4 +- integration-tests/test/general.mjs | 17 ++++-- integration-tests/test/multipleDropdowns.js | 4 +- webui.dev/js/marshaller.js | 1 + 8 files changed, 78 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index b56f4a6..150042a 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ OliveTin gives **safe** and **simple** access to predefined shell commands from [![Build Snapshot](https://github.com/OliveTin/OliveTin/actions/workflows/build-snapshot.yml/badge.svg)](https://github.com/OliveTin/OliveTin/actions/workflows/build-snapshot.yml) screenshot +More screenshots below ## Use cases diff --git a/integration-tests/Makefile b/integration-tests/Makefile index 8aee41b..9952223 100644 --- a/integration-tests/Makefile +++ b/integration-tests/Makefile @@ -1,6 +1,10 @@ -default: +default: test-install test-run + +test-install: npm install --no-fund - ./node_modules/.bin/mocha -t 5000 + +test-run: + ./node_modules/.bin/mocha -t 10000 nginx: podman-compose up -d nginx diff --git a/integration-tests/lib/elements.js b/integration-tests/lib/elements.js index 6ab8702..ac2b798 100644 --- a/integration-tests/lib/elements.js +++ b/integration-tests/lib/elements.js @@ -1,5 +1,6 @@ import { By } from 'selenium-webdriver' import fs from 'fs' +import { Condition } from 'selenium-webdriver' export async function getActionButtons (webdriver) { return await webdriver.findElement(By.id('contentActions')).findElements(By.tagName('button')) @@ -10,3 +11,17 @@ export function takeScreenshot (webdriver) { fs.writeFileSync('out.png', img, 'base64') }) } + +export async function getRootAndWait() { + await webdriver.get(runner.baseUrl()) + await webdriver.wait(new Condition('wait for initial-marshal-complete', async function() { + const body = await webdriver.findElement(By.tagName('body')) + const attr = await body.getAttribute('initial-marshal-complete') + + if (attr == 'true') { + return true + } else { + return false + } + })) +} diff --git a/integration-tests/runner.mjs b/integration-tests/runner.mjs index 71d8fef..d1de479 100644 --- a/integration-tests/runner.mjs +++ b/integration-tests/runner.mjs @@ -29,40 +29,57 @@ class OliveTinTestRunner { class OliveTinTestRunnerStartLocalProcess extends OliveTinTestRunner { async start (cfg) { + let stdout = "" + let stderr = "" + this.ot = spawn('./../OliveTin', ['-configdir', 'configs/' + cfg + '/']) const logStdout = process.env.OLIVETIN_TEST_RUNNER_LOG_STDOUT === '1' - if (logStdout) { - this.ot.stdout.on('data', (data) => { + this.ot.stdout.on('data', (data) => { + stdout += data + + if (logStdout) { console.log(`stdout: ${data}`) - }) - - this.ot.stderr.on('data', (data) => { - console.error(`stderr: ${data}`) - }) - } - - this.ot.on('close', (code) => { - if (code != null) { - console.log(`child process exited with code ${code}`) } }) - /* - this.server = await startSomeServer({port: process.env.TEST_PORT}); - console.log(`server running on port ${this.server.port}`); - */ + this.ot.stderr.on('data', (data) => { + stderr += data - this.BASE_URL = 'http://localhost:1337/' - - await waitOn({ - resources: [this.BASE_URL] + if (logStdout) { + console.log(`stderr: ${data}`) + } }) + + this.ot.on('close', (code) => { + if (code != null) { + console.log(`OliveTin local process exited with code ${code}`) + console.log(stdout) + console.log(stderr) + console.log(this.ot.exitCode) + } + }) + + if (this.ot.exitCode == null) { + this.BASE_URL = 'http://localhost:1337/' + + await waitOn({ + resources: [this.BASE_URL] + }) + + console.log(" OliveTin local process started and webUI accessible") + } else { + console.log(" OliveTin local process start FAILED!") + console.log(stdout) + console.log(stderr) + console.log(this.ot.exitCode) + } } async stop () { await this.ot.kill() + console.log(" OliveTin local process killed") } } diff --git a/integration-tests/test/entities.js b/integration-tests/test/entities.js index 53c01cf..9ce1c9d 100644 --- a/integration-tests/test/entities.js +++ b/integration-tests/test/entities.js @@ -1,7 +1,7 @@ import { describe, it, before, after } from 'mocha' import { expect } from 'chai' import { By, until } from 'selenium-webdriver' -import { takeScreenshot } from '../lib/elements.js' +import { getRootAndWait, takeScreenshot } from '../lib/elements.js' describe('config: entities', function () { before(async function () { @@ -13,7 +13,7 @@ describe('config: entities', function () { }) it('Entity buttons are rendered', async function() { - webdriver.get(runner.baseUrl()) + await getRootAndWait() const buttons = await webdriver.findElement(By.id('root-group')).findElements(By.tagName('button')) expect(buttons).to.not.be.null diff --git a/integration-tests/test/general.mjs b/integration-tests/test/general.mjs index ea384d8..46093c3 100644 --- a/integration-tests/test/general.mjs +++ b/integration-tests/test/general.mjs @@ -1,7 +1,8 @@ import { describe, it, before, after } from 'mocha' import { expect } from 'chai' -import { By } from 'selenium-webdriver' +import { By, until, Condition } from 'selenium-webdriver' //import * as waitOn from 'wait-on' +import { getRootAndWait } from '../lib/elements.js' describe('config: general', function () { before(async function () { @@ -19,6 +20,16 @@ describe('config: general', function () { expect(title).to.be.equal("OliveTin") }) + it('Page title2', async function () { + /* + await webdriver.get(runner.baseUrl()) + + const title = await webdriver.getTitle() + expect(title).to.be.equal("OliveTin") + */ + }) + + it('Footer contains promo', async function () { const ftr = await webdriver.findElement(By.tagName('footer')).getText() @@ -26,7 +37,7 @@ describe('config: general', function () { }) it('Default buttons are rendered', async function() { - await webdriver.get(runner.baseUrl()) + await getRootAndWait() const buttons = await webdriver.findElement(By.id('root-group')).findElements(By.tagName('button')) @@ -34,7 +45,7 @@ describe('config: general', function () { }) it('Start date action (popup)', async function() { - await webdriver.get(runner.baseUrl()) + await getRootAndWait() const buttons = await webdriver.findElements(By.css('[title="date-popup"]')) diff --git a/integration-tests/test/multipleDropdowns.js b/integration-tests/test/multipleDropdowns.js index d87efa8..478fce3 100644 --- a/integration-tests/test/multipleDropdowns.js +++ b/integration-tests/test/multipleDropdowns.js @@ -1,7 +1,7 @@ import { describe, it, before, after } from 'mocha' import { expect } from 'chai' import { By, until } from 'selenium-webdriver' -import { getActionButtons } from '../lib/elements.js' +import { getActionButtons, getRootAndWait } from '../lib/elements.js' describe('config: multipleDropdowns', function () { before(async function () { @@ -13,7 +13,7 @@ describe('config: multipleDropdowns', function () { }) it('Multiple dropdowns are possible', async function() { - await webdriver.get(runner.baseUrl()) + await getRootAndWait() const buttons = await getActionButtons(webdriver) diff --git a/webui.dev/js/marshaller.js b/webui.dev/js/marshaller.js index 1866d38..082457c 100644 --- a/webui.dev/js/marshaller.js +++ b/webui.dev/js/marshaller.js @@ -20,6 +20,7 @@ export function marshalDashboardComponentsJsonToHtml (json) { marshalDashboardStructureToHtml(json) document.getElementById('username').innerText = json.authenticatedUser + document.body.setAttribute('initial-marshal-complete', 'true') changeDirectory(null) }