Betterer
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843464/_untitledimage__1_.png)
Incremental Improvement
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843464/_untitledimage__1_.png)
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843503/Face.jpg)
Hi, I'm Craig!
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8944268/frame.png)
Legacy
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843547/kisspng-trinidad-black-hole-clip-art-black-hole-5abb725ca209f9.4978398315222339486637.png)
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Local Maxima
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843538/locmax-1.png)
Desired state
Current state
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Why don't we rewrite the whole thing?!
Revolution!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843566/Earth_rotation.gif)
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Revolution...
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8942138/409-4096499_earth-on-fire-png.png)
Branching!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843591/An-example-of-a-branching-timeline.png)
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Branching...
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Automation
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843659/5bee6279260063.5cbe15ae71f4e.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843696/logo.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843699/prettier-2-logo.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843701/favicon.512x512.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843703/0_SDuGCHZIYLpBeehi.png)
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Humans
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8844329/astronaut-6384598_960_720.png)
Not obsolete yet!
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Buttons
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
<button
class="button button--green">
Continue
</button>
<button
class="button button--red">
Cancel
</button>
<button
class="button button--success">
Continue
</button>
<button
class="button button--danger">
Cancel
</button>
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8944011/Screen_Shot_2021-09-21_at_13.00.27.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8944013/Screen_Shot_2021-09-21_at_13.00.58.png)
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Inspiration
![](https://images.prismic.io/inspiration4/dd687e5a-96dd-470f-8c71-9cf2132eb5e1_cargo-spaceship.png?auto=compress,format)
Evolutionary Architecture
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8844372/4fafa351839c762e519680bf51041b55.png)
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Evolutionary Algorithms
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8844155/charles_darwin-DXFGDAI6rLwzL7HhqDBMxg-removebg-preview.png)
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
A genetic representation of the solution domain:
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
---|
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
---|
1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
---|
0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 |
---|
0
Chromosome
Population
Gene
Genetic Algorithms
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
A genetic representation of the solution domain:
A fitness function to evaluate the solution:
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
---|
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
---|
1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
---|
0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 |
---|
f(chromosome) => score
Genetic Algorithms
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Termination
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
---|
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
---|
1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
---|
0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 |
---|
1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
---|
0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 |
---|
Crossover
1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
---|
0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
---|
Offspring
0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
---|
Mutation
Genetic Algorithms
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Tetris
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Evolutionary Migration?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8845067/space-4171004_1280.png)
A fitness function to evaluate the solution:
f(codebase) => score
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Code as data
import { BettererOptionsStart } from './config';
import { createGlobals } from './globals';
import { BettererRunner, BettererRunnerΩ } from './runner';
import { BettererSuiteSummary } from './suite';
// Run betterer in single-run mode:
export async function betterer(
options: BettererOptionsStart = {}
): Promise<BettererSuiteSummary> {
initDebug();
const globals = await createGlobals(options);
const runner = new BettererRunnerΩ(globals);
return runner.run(globals.config.filePaths);
}
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Code as data
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843701/favicon.512x512.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8845256/aXeLogo-300x300.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8845265/1_mn6bOs7s6Qbao15PMNRyOA.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8845291/jest.png)
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
ts(codebase) => nCompilerErrors
eslint(codebase) => nLintErrors
axe(codebase) => nA11yErrors
jest(codebase) => coverage%
f(oldScore, newScore) => better | worse | same
A comparison function to track progress:
Better?
f(codebase) => oldScore
f(codebase) => newScore
Old state of the codebase
New state of the codebase
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Codebase as database?
It has become common to store extra information about a codebase in the repository:
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@babel/code-frame@7.12.11":
version "7.12.11"
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-...
integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+...
dependencies:
"@babel/highlight" "^7.10.4"
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`betterer should not stay worse if an update is forced 1`] = `
"// BETTERER RESULTS V2.
exports[\`tsquery no raw console.log\`] = {
...
}
`
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Evolutionary Migration
A fitness function to evaluate the solution
A comparison function to track progress
A little file to store the results
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Betterer
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843464/_untitledimage__1_.png)
Incremental Improvement
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
// package.json
{
"name": "@craig/my-very-stable-package",
"version": "20.2.1",
"author": "Craig Spence <craigspence0@gmail.com>",
"description": "Gee I wish this package was a little bit better.",
"scripts": {
"betterer": "betterer",
// ...
},
// ...
"devDependencies": {
"@betterer/cli": "^5.0.0",
// ...
}
}
Initialising
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
// .betterer.ts
export default {
// Add tests here ☀️
};
Initialising
// .betterer.js
module.exports = {
// Add tests here ☀️
}
TypeScript by default:
JavaScript if you're into that:
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
My First Test
// .betterer.ts
import { BettererTest } from '@betterer/betterer';
export default {
'migrate JS to TS': () => new BettererTest({
// ...
})
};
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
My First Test
// .betterer.ts
import { BettererTest } from '@betterer/betterer';
import glob from 'glob';
export default {
'migrate JS to TS': () => new BettererTest({
test: () => glob.sync('**/*.js').length,
// ...
})
};
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
My First Test
// .betterer.ts
import { BettererTest } from '@betterer/betterer';
import { BettererConstraintResult } from '@betterer/constraints';
import glob from 'glob';
export default {
'migrate JS to TS': () => new BettererTest({
test: () => glob.sync('**/*.js').length,
constraint: (result: number, expected: number) => {
if (result < expected) {
return BettererConstraintResult.better;
}
if (result === expected) {
return BettererConstraintResult.same;
}
return BettererConstraintResult.worse;
}
})
};
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
My First Test
// .betterer.ts
import { BettererTest } from '@betterer/betterer';
import { smaller } from '@betterer/constraints';
import glob from 'glob';
export default {
'migrate JS to TS': () => new BettererTest({
test: () => glob.sync('**/*.js').length,
constraint: smaller
})
};
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
My First Result
// .betterer.results
// // BETTERER RESULTS V2.
exports[`migrate JS to TS`] = {
value: `9`
};
This is basically the same things as a Jest snapshot file!
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Workflows
Add to CI pipeline
Add to pre-commit hooks for changed files
Take their changes when merging
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
betterer precommit $1 $2 ...
betterer ci
betterer merge
// cool.js
export function ohBoyILoveJavaScript () {
console.log(`I'll never change!!!`);
return [1, 2, 3] + [4, 5, 6];
}
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8848740/comet_PNG2.png)
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8848740/comet_PNG2.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8848740/comet_PNG2.png)
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
My First File Test
// .betterer.ts
import { BettererTest } from '@betterer/betterer';
import { smaller } from '@betterer/constraints';
import glob from 'glob';
export default {
'migrate JS to TS': () => new BettererTest({
test: () => glob.sync('**/*.js').length,
constraint: smaller
})
};
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
My First File Test
// .betterer.ts
import { BettererFileTest } from '@betterer/betterer';
export default {
'migrate JS to TS': () =>
new BettererFileTest(async (filePaths, fileTestResult) => {
// ...
//
}).include('**/*.js')
};
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
My First File Test
// .betterer.ts
import { BettererFileTest } from '@betterer/betterer';
import { promises as fs } from 'fs';
export default {
'migrate JS to TS': () =>
new BettererFileTest(async (filePaths, fileTestResult) => {
await Promise.all(
filePaths.map(async (filePath) => {
const fileContents = await fs.readFile(filePath, 'utf8');
const file = fileTestResult.addFile(filePath, fileContents);
file.addIssue(0, 1, 'Please use TypeScript!');
})
);
}).include('**/**/*.js')
};
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
// BETTERER RESULTS V2.
exports[`migrate JS to TS`] = {
value: `{
"index.js:2978447364": [
[0, 0, 1, "Please use TypeScript!", "177600"]
],
"cool.js:3542870298": [
[0, 0, 1, "Please use TypeScript!", "287364"]
],
"amazing.js:8762519887": [
[0, 0, 1, "Please use TypeScript!", "726351"]
],
//...
// 9 total issues:
}`
};
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8848846/Screen_Shot_2021-08-17_at_19.02.40.png)
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
// BETTERER RESULTS V2.
exports[`migrate JS to TS`] = {
value: `{
"index.js:2978447364": [
[0, 0, 1, "Please use TypeScript!", "177600"]
],
"cool.js:3542870298": [
[0, 0, 1, "Please use TypeScript!", "287364"]
],
"amazing.js:8762519887": [
[0, 0, 1, "Please use TypeScript!", "726351"]
],
//...
// 10 total issues:
}`
};
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
// .betterer.ts
import { BettererFileTest } from '@betterer/betterer';
import { promises as fs } from 'fs';
export default {
'migrate JS to TS': () =>
new BettererFileTest(async (filePaths, fileTestResult) => {
await Promise.all(
filePaths.map(async (filePath) => {
const fileContents = await fs.readFile(filePath, 'utf8');
const file = fileTestResult.addFile(filePath, fileContents);
file.addIssue(0, 1, 'Please use TypeScript!');
})
);
})
.include('**/**/*.js')
.deadline('2021/12/31')
};
My First Deadline
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
// BETTERER RESULTS V2.
exports[`migrate JS to TS`] = {
value: `{
"index.js:2978447364": [
[0, 0, 1, "Please use TypeScript!", "177600"]
],
"boo.js:1827649983": [
[0, 0, 1, "Please use TypeScript!", "298736"]
],
"gross.js:1872646688": [
[0, 0, 1, "Please use TypeScript!", "009726"]
],
//...
// 8 total issues:
}`
};
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
More tests!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843701/favicon.512x512.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8845265/1_mn6bOs7s6Qbao15PMNRyOA.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8845276/stylelint-logo.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8846396/Microsoft.VisualStudio.Services.Icons.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8846398/127b733ca893923fc6660a2c3bcbabe2.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843703/0_SDuGCHZIYLpBeehi.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8845291/jest.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8845256/aXeLogo-300x300.png)
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
// axe.ts
export function axe () {
}
Axe Test
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
// axe.ts
import { BettererTest } from "@betterer/betterer";
export function axe () {
return new BettererTest({
// ...
});
}
Axe Test
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
// axe.ts
import { BettererTest } from "@betterer/betterer";
import { AxePuppeteer } from "axe-puppeteer";
import puppeteer from "puppeteer";
export function axe (uri: string) {
return new BettererTest({
async test() {
// ...
},
});
}
Axe Test
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
// axe.ts
import { BettererTest } from "@betterer/betterer";
import { AxePuppeteer } from "axe-puppeteer";
import puppeteer from "puppeteer";
export function axe (uri: string) {
return new BettererTest({
async test() {
const browser = await puppeteer.launch();
const [page] = await browser.pages();
await page.goto(uri);
const results = await new AxePuppeteer(page).analyze();
await page.close();
await browser.close();
return results.violations.length;
},
});
}
Axe Test
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
// axe.ts
import { BettererTest } from "@betterer/betterer";
import { smaller } from "@betterer/constraints";
import { AxePuppeteer } from "axe-puppeteer";
import puppeteer from "puppeteer";
export function axe (uri: string) {
return new BettererTest({
async test() {
// ...
return results.violations.length;
},
constraint: smaller,
});
}
Axe Test
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
// .betterer.ts
import { axe } from './axe';
export default {
'documentation homepage a11y': () =>
axe('https://phenomnomnominal.github.io/betterer'),
'documentation api a11y': () =>
axe('https://phenomnomnominal.github.io/betterer/docs/api')
};
Axe Test
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Axe Test
// BETTERER RESULTS V2.
exports[`documentation homepage a11y`] = {
value: `7`
};
exports[`documentation api a11y`] = {
value: `12`
};
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Axe Test
// axe.ts
import { BettererTest } from "@betterer/betterer";
import { AxePuppeteer } from "axe-puppeteer";
import puppeteer from "puppeteer";
export function axe (uri: string) {
return new BettererTest<BettererAxeResult>({
async test() {
// ...
return new BettererAxeResult(results.violations);
}
});
}
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Axe Test
// axe-result.ts
type BettererAxeSelectors = Array<string>;
type BettererAxeViolations = Record<string, Array<string>>;
export class BettererAxeResult {
public violations: BettererAxeViolations;
constructor (violations) {
this.violations = this._process(violations);
}
private _process (): BettererAxeViolations {
// ...
}
}
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Axe Test
// axe.ts
import { BettererConstraintResult } from '@betterer/constraints';
function constraint(
expected: BettererAxeResult,
result: BettererAxeResult
): BettererConstraintResult {
const diff = differ(expected, result);
if (diff.new.length) {
return BettererConstraintResult.worse;
}
if (diff.fixed.length) {
return BettererConstraintResult.better;
}
return BettererConstraintResult.same;
}
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Axe Test
// axe.ts
import { BettererTest } from "@betterer/betterer";
import { AxePuppeteer } from "axe-puppeteer";
import puppeteer from "puppeteer";
export function axe (uri: string) {
return new BettererTest<BettererAxeResult>({
async test() {
// ...
return new BettererAxeResult(results.violations);
},
constraint,
serialiser: {
deserialise,
serialise
}
});
}
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Axe Test
function serialise (deserialised: BettererAxeResult): BettererAxeViolations {
return deserialised.violations;
}
function deserialised (serialised: BettererAxeViolations): BettererAxeResult {
return BettererAxeResult.from(serialised);
}
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Axe Test
// BETTERER RESULTS V2.
exports[`documentation homepage a11y`] = {
value: {
"All page content must be contained by landmarks": [
"#__docusaurus > div:nth-child(2)",
".hero"
],
// ... More results
}
};
Built in tests!
// .betterer.ts
import { eslint } from '@betterer/eslint';
import { regexp } from '@betterer/regexp';
import { stylelint } from '@betterer/stylelint';
import { tsquery } from '@betterer/tsquery';
import { typescript } from '@betterer/typescript';
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Betterer
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8843464/_untitledimage__1_.png)
Help?!
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Questions?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/319854/images/8848269/moon_orig.png)
![](https://www.codeeurope.pl/static/media/logo.f455357c.png)
September 2021
Betterer: Incremental Improvement - Code Europe
By Craig Spence
Betterer: Incremental Improvement - Code Europe
- 7,831