Skip to content

Commit

Permalink
test: add tests (#9)
Browse files Browse the repository at this point in the history
adds jest + puppeteer and adds a series of tests that goes through customizing a game, exporting, and testing that the hacked game works. note that the tests are all done in a single run, not isolated, and primarily use image snapshots (this isn't best practice, but is quicker/easier and should be good enough for the coverage we'd care about)
  • Loading branch information
seleb committed Oct 11, 2021
1 parent 9319196 commit 9bbca21
Show file tree
Hide file tree
Showing 17 changed files with 8,120 additions and 3 deletions.
7,944 changes: 7,943 additions & 1 deletion package-lock.json

Large diffs are not rendered by default.

15 changes: 13 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"description": "Borksy Game Hacker: A tool for extending Bitsy games",
"scripts": {
"preversion": "npm run build",
"build": "rm -r -f ./docs && cp -r ./src ./docs && rm ./docs/about/*.md",
"test": "echo \"Error: no test specified\" && exit 1"
"build": "rm -r -f ./docs && cp -r ./src ./docs && rm ./docs/about/*.md && rm -r ./docs/test",
"test": "jest --runInBand"
},
"repository": {
"type": "git",
Expand All @@ -18,6 +18,12 @@
"url": "https://github.com/Ayolland/borksy/issues"
},
"homepage": "https://ayolland.itch.io/borksy",
"jest": {
"testEnvironment": "jsdom",
"setupFilesAfterEnv": [
"<rootDir>/src/test/setupTests.js"
]
},
"release": {
"plugins": [
"@semantic-release/commit-analyzer",
Expand All @@ -37,5 +43,10 @@
}
]
]
},
"devDependencies": {
"jest": "^27.2.5",
"jest-image-snapshot": "^4.5.1",
"puppeteer": "^10.4.0"
}
}
1 change: 1 addition & 0 deletions src/test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.html
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
157 changes: 157 additions & 0 deletions src/test/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
const path = require('path');
const puppeteer = require('puppeteer');
const fs = require('fs');

describe('Borksy', () => {
/** @type puppeteer.Browser */
let browser;
/** @type puppeteer.Page */
let page;

const download = path.resolve(__dirname, 'myBORKSYgameCustomFilename.html');

beforeAll(async () => {
browser = await puppeteer.launch({
headless: false,
args: ['--disable-web-security', '--disable-features=IsolateOrigins', ' --disable-site-isolation-trials'],
});
page = await browser.newPage();

await page._client.send('Page.setDownloadBehavior', { behavior: 'allow', downloadPath: path.resolve(__dirname) });
await page.goto(`file:///${path.resolve(__dirname, '../../docs/index.html').replace(/\\/g, '/')}`, {
waitUntil: 'networkidle2',
});

// hide mascot to avoid noise in snapshots
await page.evaluate(() => {
document.querySelector('#mascot').style.visibility = 'hidden';
});
});

afterAll(async () => {
await browser.close();
});

it('should load', async () => {
expect(await page.screenshot()).toMatchImageSnapshot();
});

it('should collapse sections when clicked', async () => {
await page.click('#about .collapsible_header');
expect(await page.screenshot()).toMatchImageSnapshot();
});

it('should allow game to be customized', async () => {
// fill out game data
await page.click('form > .collapsible:first-of-type > .collapsible_header'); // open title
await page.type('#title', 'Custom Title');
await page.type('#filename', 'Custom Filename');
expect(await page.screenshot()).toMatchImageSnapshot();

// remove collision on walls
await page.click('form > .collapsible:nth-of-type(3) > .collapsible_header'); // open gamedata
await page.focus('#gamedata');
await page.keyboard.down('Control');
await page.keyboard.press('Home');
await page.keyboard.up('Control');
for (let i = 0; i < 39; ++i) {
await page.keyboard.press('ArrowDown');
}
await page.keyboard.down('Shift');
await page.keyboard.press('ArrowDown');
await page.keyboard.up('Shift');
await page.keyboard.press('Backspace');
expect(await page.screenshot()).toMatchImageSnapshot();

// enable transparent sprites hack
await page.click('#hacks-section > .collapsible_header'); // open hacks
await page.click('.collapsible[data-associated-hack="transparent-sprites"] > .collapsible_header'); // open transparent sprites
await page.click('.collapsible[data-associated-hack="transparent-sprites"] input[type="checkbox"]'); // click checkbox
await page.click('.collapsible[data-associated-hack="transparent-sprites"] .collapsible:first-of-type > .collapsible_header'); // open hack options
expect(await page.screenshot()).toMatchImageSnapshot();

// customize `isTransparent` check in `gameOptions`
await page.focus('.collapsible[data-associated-hack="transparent-sprites"] [data-default-type="hackOptions"]');
await page.keyboard.down('Control');
await page.keyboard.press('Home');
await page.keyboard.up('Control');
await page.keyboard.press('End');
await page.keyboard.type('\n\treturn drawing === player();');
expect(await page.screenshot()).toMatchImageSnapshot();
});

it('should include hack READMEs', async () => {
await page.click('.collapsible[data-associated-hack="transparent-sprites"] .collapsible:last-of-type > .collapsible_header');
expect(await page.screenshot()).toMatchImageSnapshot();
});

it('should allow custom javascript to be added', async () => {
await page.click('form > .collapsible:last-of-type > .collapsible_header'); // open additional js
await page.focus('#additionalJS');
await page.keyboard.type(`
requestAnimationFrame(() => {
var el = document.createElement('div');
el.textContent = 'test';
el.style.position = 'fixed';
el.style.top = '0';
el.style.left = '0';
el.style.color='white';
document.body.appendChild(el);
});
`);
expect(await page.screenshot()).toMatchImageSnapshot();
});

it('should allow game to be downloaded', async () => {
// remove download if we already have one
if (fs.existsSync(download)) {
await fs.promises.unlink(download);
}

await page.click('#download-button'); // start download
await page.waitForTimeout(2000); // wait for download to finish
expect(fs.existsSync(download)).toBe(true);
});

it('should produce a playable game', async () => {
await page.goto(`file:///${download.replace(/\\/g, '/')}`, {
waitUntil: 'networkidle2',
});
await page.keyboard.down('ArrowRight'); // complete title dialog
await page.waitForTimeout(100);
await page.keyboard.up('ArrowRight'); // complete title dialog
await page.waitForTimeout(100);
expect(await page.screenshot()).toMatchImageSnapshot();
await page.keyboard.down('ArrowRight'); // end title dialog
await page.waitForTimeout(100);
await page.keyboard.up('ArrowRight'); // end title dialog
await page.waitForTimeout(100);
expect(await page.screenshot()).toMatchImageSnapshot();
});

it('should produce a game with hacks applied', async () => {
// walk on top of wall to demonstrate transparent sprites
await page.keyboard.down('ArrowLeft');
await page.waitForTimeout(100);
await page.keyboard.up('ArrowLeft');
await page.waitForTimeout(100);
await page.keyboard.down('ArrowLeft');
await page.waitForTimeout(100);
await page.keyboard.up('ArrowLeft');
await page.waitForTimeout(100);
await page.keyboard.down('ArrowLeft');
await page.waitForTimeout(100);
await page.keyboard.up('ArrowLeft');
await page.waitForTimeout(100);
expect(await page.screenshot()).toMatchImageSnapshot();
});

it('should include customized hackOptions', async () => {
// move dog onto wall to demonstrate `isTransparent` check
await page.evaluate(() => {
window.sprite.a.x = 1;
});
await page.waitForTimeout(100);
expect(await page.screenshot()).toMatchImageSnapshot();
});
});
6 changes: 6 additions & 0 deletions src/test/setupTests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const { toMatchImageSnapshot } = require('jest-image-snapshot');

expect.extend({
toMatchImageSnapshot,
});
jest.setTimeout(20000);

0 comments on commit 9bbca21

Please sign in to comment.