index : btroops | |
Virtual board game-aid for BattleTroops, an infantry combat simulator wargame published by FASA in 1989. |
aboutsummaryrefslogtreecommitdiff |
diff options
author | Catalin Mititiuc <webdevcat@proton.me> | 2024-06-01 17:50:58 -0700 |
---|---|---|
committer | Catalin Mititiuc <webdevcat@proton.me> | 2024-06-01 17:50:58 -0700 |
commit | 163e3a9de59f5d6a8df38fa32a1e7dc4db1ad024 (patch) | |
tree | 8ae679d3059d8ee8c69a3d45994bc74e4388f76b | |
parent | e8fae51b32b6ebc4ec4e16338467b7fcc41edd11 (diff) |
Fix/refactor tests
-rw-r--r-- | esbuild-server.mjs | 4 | ||||
-rw-r--r-- | jest.config.integ.cjs | 3 | ||||
-rwxr-xr-x | node | 20 | ||||
-rwxr-xr-x | npm | 20 | ||||
-rwxr-xr-x | run-shell | 3 | ||||
-rwxr-xr-x | run-shell-test | 3 | ||||
-rwxr-xr-x | scripts/docker-run | 13 | ||||
-rw-r--r-- | server.cjs | 49 | ||||
-rw-r--r-- | src/index.js | 21 | ||||
-rw-r--r-- | src/modules/gameboard.js | 8 | ||||
-rw-r--r-- | src/modules/record_sheet.js | 5 | ||||
-rw-r--r-- | test/integration/helpers.cjs | 5 | ||||
-rw-r--r-- | test/integration/page.test.js | 8 | ||||
-rw-r--r-- | test/integration/select.test.js | 127 | ||||
-rw-r--r-- | test/integration/setup.cjs | 4 |
15 files changed, 159 insertions, 134 deletions
diff --git a/esbuild-server.mjs b/esbuild-server.mjs index 0f169f3..2421f23 100644 --- a/esbuild-server.mjs +++ b/esbuild-server.mjs @@ -155,9 +155,6 @@ const resolveSvgImports = { name: 'resolveSvgImports', setup(build) { build.onStart(() => { - console.log("BUILD STARTED"); - console.log(build.initialOptions.outdir); - fs.rmSync(path.resolve(build.initialOptions.outdir), { recursive: true, force: true }); }); @@ -228,7 +225,6 @@ const ctx = await esbuild.context({ '.svg': 'file' }, assetNames: 'assets/images/[name]-[hash]', - metafile: true }); await ctx.watch(); diff --git a/jest.config.integ.cjs b/jest.config.integ.cjs index 7e8af3c..28562ea 100644 --- a/jest.config.integ.cjs +++ b/jest.config.integ.cjs @@ -6,4 +6,7 @@ module.exports = { setupFiles: ['./test/integration/helpers.cjs'], testPathIgnorePatterns: ['/node_modules/', 'test/unit'], testTimeout: 5000, + globals: { + testServerUrl: 'http://localhost:3005/' + } }; @@ -1,13 +1,15 @@ #!/usr/bin/env bash -user_id=$(id -u) -image=btroops +#user_id=$(id -u) +#image=btroops -if [[ $1 == run && $2 == test* ]] -then - port=3005 -else - port=8080 -fi +#if [[ $1 == run && $2 == test* ]] +#then +# port=3005 +#else +# port=8080 +#fi -docker run --rm --init -it -v $PWD:/usr/src/app -u $user_id:$user_id -p $port:$port $image node $@ +#docker run --rm --init -it -v $PWD:/usr/src/app -u $user_id:$user_id -p $port:$port $image node $@ + +source ./scripts/docker-run node $@ @@ -1,13 +1,15 @@ #!/usr/bin/env bash -user_id=$(id -u) -image=btroops +#user_id=$(id -u) +#image=btroops -if [[ $1 == run && $2 == test* ]] -then - port=3005 -else - port=8080 -fi +#if [[ $1 == run && $2 == test* ]] +#then +# port=3005 +#else +# port=8080 +#fi -docker run --rm --init -it -v $PWD:/usr/src/app -u $user_id:$user_id -p $port:$port $image npm $@ +#docker run --rm --init -it -v $PWD:/usr/src/app -u $user_id:$user_id -p $port:$port $image npm $@ + +source ./scripts/docker-run npm $@ diff --git a/run-shell b/run-shell deleted file mode 100755 index afd0141..0000000 --- a/run-shell +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -docker run --rm --init -it -v $PWD:/usr/src/app -p 8080:8080 btroops bash diff --git a/run-shell-test b/run-shell-test deleted file mode 100755 index 8d1edd7..0000000 --- a/run-shell-test +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -docker run --rm --init -it --hostname btroops-test -v $PWD:/usr/src/app -p 8080:8080 --name btroops-test btroops bash diff --git a/scripts/docker-run b/scripts/docker-run new file mode 100755 index 0000000..a11ce87 --- /dev/null +++ b/scripts/docker-run @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +user_id=$(id -u) +image=btroops + +if [[ $2 == run && $3 == test* ]] +then + port=3005 +else + port=8080 +fi + +docker run --rm --init -it -v $PWD:/usr/src/app -u $user_id:$user_id -p $port:$port $image $@ @@ -1,5 +1,24 @@ const { createServer } = require('esbuild-server'); const path = require('node:path'); +const fs = require('node:fs'); +const { IncomingMessage } = require('node:http'); + +class Request extends IncomingMessage { + constructor(socket) { + super(socket); + } + + get url() { + console.log('getter called', this._url); + return this._url; + } + + set url(val) { + console.log('setter called', val); + this._url = val; + } +} + const resolveImportedSvg = { name: 'resolveImportedSvg', @@ -12,21 +31,36 @@ const resolveImportedSvg = { } } +const resolveSvgImports = { + name: 'resolveSvgImports', + setup(build) { + build.onStart(() => { + fs.rmSync(path.resolve(build.initialOptions.outdir), { recursive: true, force: true }); + }); + + build.onResolve({ filter: /\.svg$/ }, args => { + return { + path: path.resolve('public', args.path), + }; + }); + } +} + const server = createServer( { bundle: true, define: { 'env': `"${process.env.NODE_ENV || 'dev'}"`, }, - entryPoints: ['src/*.js'], - ...(process.env.NODE_ENV !== 'test') && { - outdir: 'build' - }, - plugins: [resolveImportedSvg], + entryPoints: ['src/index.js', 'src/soldier_record_block.js', 'src/map.js'], + outdir: 'build', + // ...(process.env.NODE_ENV !== 'test') && { + // outdir: 'build' + // }, + plugins: [resolveSvgImports], loader: { '.svg': 'file' }, - metafile: true, assetNames: 'assets/images/[name]-[hash]', }, { @@ -34,7 +68,8 @@ const server = createServer( ...(process.env.NODE_ENV === 'test') && { port: 3005, injectLiveReload: false, - watch: false + watch: false, + // http: { IncomingMessage: Request } } } ); diff --git a/src/index.js b/src/index.js index e638910..7f914d4 100644 --- a/src/index.js +++ b/src/index.js @@ -80,11 +80,20 @@ function loadScenario(data) { async function buildScenario(req) { console.log('req', req); + console.log('fresh template', scenarioTemplate.querySelector('svg')); + const svg = scenarioTemplate.querySelector('svg').cloneNode(true); - document.querySelector('object').contentDocument.querySelector('svg').replaceWith(svg); - const startLocs = svg.querySelector('.start-locations'); + // console.log('document', document.querySelector('object').contentDocument); + + document.querySelector('object').contentDocument.querySelector('svg').remove(); + document.querySelector('object').contentDocument.append(svg); + + gameboard.stop(); + recordSheet.stop(); + const scenario = await req; + const startLocs = scenario.querySelector('.start-locations'); console.log(scenario); @@ -119,17 +128,15 @@ async function buildScenario(req) { }); const refsQuery = [...refs[filename]].join(', '); - external.querySelectorAll(refsQuery).forEach(node => defs.append(node)); + external.querySelectorAll(refsQuery).forEach(node => defs.append(svg.ownerDocument.importNode(node, true))); }); }); - scenario.querySelectorAll('use.mapsheet').forEach(el => gb.prepend(el)); - grid.before(scenario.querySelector('.start-locations')); + scenario.querySelectorAll('use.mapsheet').forEach(el => gb.prepend(svg.ownerDocument.importNode(el, true))); + if (startLocs) grid.before(svg.ownerDocument.importNode(startLocs, true)); const scenarioGrid = scenario.querySelector('.grid'); - console.log('scenarioGrid', scenarioGrid); - if (scenarioGrid) { grid.replaceWith(svg.ownerDocument.importNode(scenarioGrid, true)); } diff --git a/src/modules/gameboard.js b/src/modules/gameboard.js index 38a9a9a..97538cd 100644 --- a/src/modules/gameboard.js +++ b/src/modules/gameboard.js @@ -175,6 +175,7 @@ function selectOffBoard() { } function select(data) { + console.log('select', data); const counter = data && (soldier.getCounter(svg, data) || soldier.createCounter(data)); const isSelected = counter?.classList.contains(soldier.getSelectedClass()); @@ -204,6 +205,8 @@ export function start(el) { startingLocations && getUnits(startingLocations).forEach(unit => unit.addEventListener('click', selectOffBoard)); getCells(svg).forEach(cell => { + if (cell.dataset.x === '0' && cell.parentElement.dataset.y === '0') console.log('cell', cell); + cell.addEventListener('click', e => { const occupant = getCellOccupant(cell); let toPlace = placing.pop(); @@ -300,6 +303,11 @@ export function start(el) { console.log('gameboard.js loaded'); } +export function stop() { + Observable.unsubscribe('select', select); + Observable.unsubscribe('endmove', endMove); +} + export function getUnits() { return soldier.getAllCounters(svg); } diff --git a/src/modules/record_sheet.js b/src/modules/record_sheet.js index 33a21fe..53f6d83 100644 --- a/src/modules/record_sheet.js +++ b/src/modules/record_sheet.js @@ -195,3 +195,8 @@ export function start(startLoc, units) { Observable.subscribe('select', select); Observable.subscribe('endmove', endMove); } + +export function stop() { + Observable.unsubscribe('select', select); + Observable.unsubscribe('endmove', endMove); +} diff --git a/test/integration/helpers.cjs b/test/integration/helpers.cjs index 5643bfd..7e3e0fd 100644 --- a/test/integration/helpers.cjs +++ b/test/integration/helpers.cjs @@ -9,3 +9,8 @@ global.takeScreenshot = async (driver) => { await mkdir(dir, { recursive: true }); await writeFile(`${dir}/${fileName.replaceAll('/', '-')}`, image, 'base64'); }; + +global.url = (relativeOrAbsolute) => { + const location = new URL(relativeOrAbsolute, global.testServerUrl); + return location.href; +} diff --git a/test/integration/page.test.js b/test/integration/page.test.js index 8bb703e..f06a7d1 100644 --- a/test/integration/page.test.js +++ b/test/integration/page.test.js @@ -1,7 +1,6 @@ const { Builder } = require('selenium-webdriver'), chrome = require('selenium-webdriver/chrome.js'), - chromeOptions = new chrome.Options(), - { expect, it } = require('@jest/globals'); + chromeOptions = new chrome.Options(); chromeOptions.addArguments('--headless', '--disable-gpu', '--no-sandbox'); chromeOptions.enableBidi(); @@ -9,11 +8,12 @@ chromeOptions.enableBidi(); let driver; beforeEach(async () => { - driver = new Builder().forBrowser('chrome').setChromeOptions(chromeOptions).build(); + const builder = new Builder().forBrowser('chrome').setChromeOptions(chromeOptions); + driver = builder.build(); }); it('loads the page', async () => { - await driver.get('http://localhost:3005'); + await driver.get(url('/')); expect(await driver.getTitle()).toEqual('Infantry Combat Solo Basic'); }); diff --git a/test/integration/select.test.js b/test/integration/select.test.js index 2594179..d9b632e 100644 --- a/test/integration/select.test.js +++ b/test/integration/select.test.js @@ -1,44 +1,49 @@ const { Builder, By, until } = require('selenium-webdriver'), chrome = require('selenium-webdriver/chrome.js'), chromeOptions = new chrome.Options(), - { expect, it } = require('@jest/globals'), - { readFile } = require('node:fs/promises'), + { readFile, readdir } = require('node:fs/promises'), { HttpResponse } = require('selenium-webdriver/devtools/networkinterceptor'); chromeOptions.addArguments('--headless', '--disable-gpu', '--no-sandbox'); -chromeOptions.enableBidi(); -let driver; +const buildPath = 'build/assets/images'; +const defaultScenario = 'scenario-side_show'; +const fixtureFilePath = './test/integration/fixtures/scenario-test.svg'; -beforeEach(async () => { - driver = new Builder().forBrowser('chrome').setChromeOptions(chromeOptions).build(); -}); +const selected = expect.stringContaining('selected'); +const notSelected = expect.not.stringContaining('selected'); -it('selects and deselects a trooper by clicking on its counter', async () => { - const connection = await driver.createCDPConnection('page') - const url = 'http://localhost:3005/assets/images/scenario-side_show.svg'; - const httpResponse = new HttpResponse(url); - httpResponse.body = await readFile('./test/integration/fixtures/scenario-test.svg', 'utf8'); +let driver, httpResponse; + +beforeAll(async () => { + const filenames = await readdir(buildPath); + const scenario = filenames.find(filename => filename.includes(defaultScenario)); + + httpResponse = new HttpResponse(url(`/assets/images/${scenario}`)); + httpResponse.body = await readFile(fixtureFilePath, 'utf8'); httpResponse.addHeaders('Content-Type', 'image/svg+xml'); +}); +beforeEach(async () => { + driver = new Builder().forBrowser('chrome').setChromeOptions(chromeOptions).build(); + const connection = await driver.createCDPConnection('page') await driver.onIntercept(connection, httpResponse, async () => {}); - await driver.get('http://localhost:3005'); - await driver.wait(until.elementLocated(By.css('#dice')), 1000); + await driver.get(url('/')); + const mapPlaceholderEl = await driver.findElement(By.css('.map-placeholder')); + await driver.wait(until.elementIsNotVisible(mapPlaceholderEl), 1000); +}); +it('selects and deselects a trooper by clicking on its counter', async () => { const record = await driver.findElement(By.css('.soldier-record')); - const notSelected = expect.not.stringContaining('selected'); + const objectEl = await driver.findElement(By.css('object')); + const selector = '.counter[data-allegiance="attacker"][data-number="1"]'; expect(await record.getAttribute('class')).toEqual(notSelected); - - const objectEl = await driver.findElement(By.css('object')); await driver.switchTo().frame(objectEl); - - const selector = '.counter[data-allegiance="attacker"][data-number="1"]', - svg = await driver.findElement(By.css('svg')), - counter = await driver.findElement(By.css(selector), svg), - selected = expect.stringContaining('selected'); - + const svg = await driver.findElement(By.css('svg')); + const counter = await driver.findElement(By.css(selector), svg); expect(await counter.getAttribute('class')).toEqual(notSelected); + await counter.click(); expect(await counter.getAttribute('class')).toEqual(selected); @@ -54,37 +59,20 @@ it('selects and deselects a trooper by clicking on its counter', async () => { }); it('selects and deselects trooper by clicking on its record', async () => { - const connection = await driver.createCDPConnection('page') - const url = 'http://localhost:3005/assets/images/scenario-side_show.svg'; - const httpResponse = new HttpResponse(url); - httpResponse.body = await readFile('./test/integration/fixtures/scenario-test.svg', 'utf8'); - httpResponse.addHeaders('Content-Type', 'image/svg+xml'); - - await driver.onIntercept(connection, httpResponse, async () => {}); - await driver.get('http://localhost:3005'); - await driver.wait(until.elementLocated(By.css('#dice')), 1000); - const record = await driver.findElement(By.css('.soldier-record')); - const notSelected = expect.not.stringContaining('selected'); + const objectEl = await driver.findElement(By.css('object')); + const selector = '.counter[data-allegiance="attacker"][data-number="1"]'; expect(await record.getAttribute('class')).toEqual(notSelected); - - const objectEl = await driver.findElement(By.css('object')); await driver.switchTo().frame(objectEl); - - const selector = '.counter[data-allegiance="attacker"][data-number="1"]', - svg = await driver.findElement(By.css('svg')), - counter = await driver.findElement(By.css(selector), svg); - + const svg = await driver.findElement(By.css('svg')); + const counter = await driver.findElement(By.css(selector), svg); expect(await counter.getAttribute('class')).toEqual(notSelected); await driver.switchTo().defaultContent(); await record.click(); - const selected = expect.stringContaining('selected'); - expect(await record.getAttribute('class')).toEqual(selected); - await driver.switchTo().frame(objectEl); expect(await counter.getAttribute('class')).toEqual(selected); @@ -92,36 +80,21 @@ it('selects and deselects trooper by clicking on its record', async () => { await record.click(); expect(await record.getAttribute('class')).toEqual(notSelected); - await driver.switchTo().frame(objectEl); expect(await counter.getAttribute('class')).toEqual(notSelected); }); it('selects a trooper by clicking on its counter and deselects it by clicking on its record', async () => { - const connection = await driver.createCDPConnection('page') - const url = 'http://localhost:3005/assets/images/scenario-side_show.svg'; - const httpResponse = new HttpResponse(url); - httpResponse.body = await readFile('./test/integration/fixtures/scenario-test.svg', 'utf8'); - httpResponse.addHeaders('Content-Type', 'image/svg+xml'); - - await driver.onIntercept(connection, httpResponse, async () => {}); - await driver.get('http://localhost:3005'); - await driver.wait(until.elementLocated(By.css('#dice')), 1000); - const record = await driver.findElement(By.css('.soldier-record')); - const notSelected = expect.not.stringContaining('selected'); + const objectEl = await driver.findElement(By.css('object')); + const selector = '.counter[data-allegiance="attacker"][data-number="1"]'; expect(await record.getAttribute('class')).toEqual(notSelected); - - const objectEl = await driver.findElement(By.css('object')); await driver.switchTo().frame(objectEl); - - const selector = '.counter[data-allegiance="attacker"][data-number="1"]', - svg = await driver.findElement(By.css('svg')), - counter = await driver.findElement(By.css(selector), svg), - selected = expect.stringContaining('selected'); - + const svg = await driver.findElement(By.css('svg')); + const counter = await driver.findElement(By.css(selector), svg); expect(await counter.getAttribute('class')).toEqual(notSelected); + await counter.click(); expect(await counter.getAttribute('class')).toEqual(selected); @@ -131,43 +104,25 @@ it('selects a trooper by clicking on its counter and deselects it by clicking on await record.click(); expect(await record.getAttribute('class')).toEqual(notSelected); - await driver.switchTo().frame(objectEl); expect(await counter.getAttribute('class')).toEqual(notSelected); }); it('selects a trooper by clicking on its record and deselects it by clicking on its counter', async () => { - const connection = await driver.createCDPConnection('page') - const url = 'http://localhost:3005/assets/images/scenario-side_show.svg'; - const httpResponse = new HttpResponse(url); - httpResponse.body = await readFile('./test/integration/fixtures/scenario-test.svg', 'utf8'); - httpResponse.addHeaders('Content-Type', 'image/svg+xml'); - - await driver.onIntercept(connection, httpResponse, async () => {}); - await driver.get('http://localhost:3005'); - await driver.wait(until.elementLocated(By.css('#dice')), 1000); - const record = await driver.findElement(By.css('.soldier-record')); - const notSelected = expect.not.stringContaining('selected'); + const objectEl = await driver.findElement(By.css('object')); + const selector = '.counter[data-allegiance="attacker"][data-number="1"]'; expect(await record.getAttribute('class')).toEqual(notSelected); - - const objectEl = await driver.findElement(By.css('object')); await driver.switchTo().frame(objectEl); - - const selector = '.counter[data-allegiance="attacker"][data-number="1"]', - svg = await driver.findElement(By.css('svg')), - counter = await driver.findElement(By.css(selector), svg); - + const svg = await driver.findElement(By.css('svg')); + const counter = await driver.findElement(By.css(selector), svg); expect(await counter.getAttribute('class')).toEqual(notSelected); await driver.switchTo().defaultContent(); await record.click(); - const selected = expect.stringContaining('selected'); - expect(await record.getAttribute('class')).toEqual(selected); - await driver.switchTo().frame(objectEl); expect(await counter.getAttribute('class')).toEqual(selected); diff --git a/test/integration/setup.cjs b/test/integration/setup.cjs index 2ea9e63..cc68a59 100644 --- a/test/integration/setup.cjs +++ b/test/integration/setup.cjs @@ -1,7 +1,7 @@ console.log('\nSpawning server process...'); const { spawn } = require('child_process'); -module.exports = async function () { +module.exports = async function (globalConfig, projectConfig) { const child = spawn('node', ['server.cjs']); child.stdout.on('data', (data) => { @@ -13,7 +13,7 @@ module.exports = async function () { child.stderr.on('data', (data) => { const str = data.toString(); console.log('[server]', str); - if (str.includes('localhost:3005')) { + if (str.includes(projectConfig.globals.testServerUrl)) { setTimeout(resolve, 200); } }); |