Skip to content

Commit

Permalink
docs: explain snapshot testing (#1010)
Browse files Browse the repository at this point in the history
* chore: use Biome instead of prettier+eslint

* docs: explain snapshot testing

* move biome to dev deps

* link library
  • Loading branch information
ematipico authored Jun 20, 2024
1 parent 4e7cc82 commit ead5809
Show file tree
Hide file tree
Showing 103 changed files with 551 additions and 1,021 deletions.
19 changes: 0 additions & 19 deletions .eslintrc.cjs

This file was deleted.

11 changes: 5 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
- uses: actions/setup-node@v4
- name: Setup Biome
uses: biomejs/setup-biome@v2
with:
node-version: 16
cache: 'pnpm'
- run: pnpm install
- run: pnpm run lint
version: latest
- name: Run linting
run: biome ci --diagnostic-level=warn
7 changes: 0 additions & 7 deletions .prettierrc

This file was deleted.

61 changes: 57 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,68 @@ When adding a new feature or debugging an issue, start at the tokenizer, then mo

## Tests

### Running

- Run all tests: `go test -v ./internal/...`
- Run a specific folder of tests: `go test -v ./internal/printer`
It's important to **run the test from the root of the project**. Doing so, `go` will load all the necessary global information needed to run the tests.

### Run all tests

```shell
go test -v ./internal/...
```
### Run a specific test suite

```shell
go test -v ./internal/printer
```
### Run a specific test case

Many of your test cases are designed like this:

```go
func TestPrintToJSON(t *testing.T) {
tests := []jsonTestcase{
{
name: "basic",
source: `<h1>Hello world!</h1>`,
want: []ASTNode{{Type: "element", Name: "h1", Children: []ASTNode{{Type: "text", Value: "Hello world!"}}}},
},
{
name: "Comment preserves whitespace",
source: `<!-- hello -->`,
want: []ASTNode{{Type: "comment", Value: " hello "}},
}
}
}
```

In this particular instance, the test case is name of the function, a slash `/`, followed by the `name` field. If the test case has spaces, you can use them.

```shell
go test -v ./internal/... -run TestPrintToJSON/basic
go test -v ./internal/... -run TestPrintToJSON/Comment preserves whitespace
```

### Adding new tests

Adding tests for the tokenizer, scanner, and printer can be found in `internal/token_test.go`, `internal/js_scanner_test.go`, and `internal/printer/printer_test.go`, respectively.

### Snapshot testing

We use [go-snaps](https://github.com/gkampitakis/go-snaps) for snapshot testing. Visit their repository for more details on how to use it

#### Update snapshots

Some of our tests use snapshot tests. If some of you changes are expected to update some snapshot tests, you can use the environment variable `UPDATE_SNAPS` to do so:

```shell
UPDATE_SNAPS=true go test -v ./internal/...
```

Instead, if there are some **obsolete snapshots**, you can `UPDATE_SNAPS=clean`:

```shell
UPDATE_SNAPS=clean go test -v ./internal/...
```

[homebrew]: https://brew.sh/
[go]: https://golang.org/
[go-vscode]: https://marketplace.visualstudio.com/items?itemName=golang.go
Expand Down
52 changes: 52 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"$schema": "https://biomejs.dev/schemas/1.8.1/schema.json",
"files": {
"ignore": ["**/dist", "**/pnpm-lock.yaml"],
"include": ["packages/**"]
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 180
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noExplicitAny": "info",
"noConsoleLog": "info"
},
"style": {
"useTemplate": {
"level": "error",
"fix": "safe"
},
"noUnusedTemplateLiteral": {
"level": "error",
"fix": "safe"
}
}
},
"ignore": ["wasm_exec.ts"]
},
"javascript": {
"formatter": {
"quoteStyle": "single"
}
},
"overrides": [
{
"include": ["package.json", "biome.jsonc"],
"json": {
"formatter": {
"lineWidth": 1
}
}
}
]
}
14 changes: 5 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
"build": "make wasm",
"build:compiler": "pnpm --filter @astrojs/compiler run build",
"build:all": "pnpm run build && pnpm run build:compiler",
"lint": "eslint \"packages/**/src/**/*.{cjs,js,jsx,mjs,ts,tsx}\"",
"format": "prettier -w .",
"check": "biome check",
"ci": "biome ci --diagnostic-level=warn",
"check:write": "biome check --write",
"prerelease": "pnpm run build:compiler",
"release": "changeset publish",
"test": "tsx node_modules/uvu/bin.js packages test -i utils -i stress",
Expand All @@ -25,16 +26,11 @@
],
"devDependencies": {
"@changesets/cli": "^2.25.0",
"@typescript-eslint/eslint-plugin": "^5.57.1",
"@typescript-eslint/parser": "^5.57.1",
"eslint": "^8.25.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"prettier": "^2.8.7",
"sass": "^1.55.0",
"tsx": "^3.10.1",
"typescript": "~4.9.0",
"uvu": "^0.5.6"
"uvu": "^0.5.6",
"@biomejs/biome": "1.8.1"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler/src/browser/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const initialize: typeof types.initialize = async (options) => {
longLivedService = longLivedService || (await initializePromise);
};

let ensureServiceIsRunning = (): Service => {
const ensureServiceIsRunning = (): Service => {
if (!initializePromise) throw new Error('You need to call "initialize" before calling this');
if (!longLivedService) throw new Error('You need to wait for the promise returned from "initialize" to be resolved before calling this');
return longLivedService;
Expand Down
26 changes: 15 additions & 11 deletions packages/compiler/src/browser/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ import type {
TextNode,
} from '../shared/ast';

export interface Visitor {
(node: Node, parent?: ParentNode, index?: number): void | Promise<void>;
}
export type Visitor = (node: Node, parent?: ParentNode, index?: number) => void | Promise<void>;

function guard<Type extends Node>(type: string) {
return (node: Node): node is Type => node.type === type;
Expand Down Expand Up @@ -53,7 +51,7 @@ class Walker {
async visit(node: Node, parent?: ParentNode, index?: number): Promise<void> {
await this.callback(node, parent, index);
if (is.parent(node)) {
let promises = [];
const promises = [];
for (let i = 0; i < node.children.length; i++) {
const child = node.children[i];
promises.push(this.callback(child, node as ParentNode, i));
Expand Down Expand Up @@ -112,25 +110,31 @@ export function serialize(root: Node, opts: SerializeOptions = { selfClose: true
let output = '';
function visitor(node: Node) {
if (is.root(node)) {
node.children.forEach((child) => visitor(child));
for (const child of node.children) {
visitor(child);
}
} else if (is.frontmatter(node)) {
output += `---${node.value}---\n\n`;
} else if (is.comment(node)) {
output += `<!--${node.value}-->`;
} else if (is.expression(node)) {
output += `{`;
node.children.forEach((child) => visitor(child));
output += `}`;
output += '{';
for (const child of node.children) {
visitor(child);
}
output += '}';
} else if (is.literal(node)) {
output += node.value;
} else if (is.tag(node)) {
output += `<${node.name}`;
output += serializeAttributes(node);
if (node.children.length == 0 && opts.selfClose) {
output += ` />`;
if (node.children.length === 0 && opts.selfClose) {
output += ' />';
} else {
output += '>';
node.children.forEach((child) => visitor(child));
for (const child of node.children) {
visitor(child);
}
output += `</${node.name}>`;
}
}
Expand Down
15 changes: 7 additions & 8 deletions packages/compiler/src/browser/wasm_exec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable */
// @ts-nocheck
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
Expand Down Expand Up @@ -152,7 +151,7 @@ Object.defineProperties(globalThis, {

const encoder = new TextEncoder('utf-8');
const decoder = new TextDecoder('utf-8');
let logLine = [];
const logLine = [];

export default class Go {
public importObject;
Expand Down Expand Up @@ -334,8 +333,8 @@ export default class Go {
this._resume();
}
},
getInt64(sp + 8) + 1 // setTimeout has been seen to fire up to 1 millisecond early
)
getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early
),
);
this.mem.setInt32(sp + 16, id, true);
},
Expand Down Expand Up @@ -460,7 +459,7 @@ export default class Go {
// func valueLength(v ref) int
'syscall/js.valueLength': (sp) => {
sp >>>= 0;
setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
setInt64(sp + 16, Number.parseInt(loadValue(sp + 8).length));
},

// valuePrepareString(v ref) (ref, int)
Expand Down Expand Up @@ -529,15 +528,15 @@ export default class Go {
this.mem = new DataView(this._inst.exports.mem.buffer);
this._values = [
// JS values that Go currently has references to, indexed by reference id
NaN,
Number.NaN,
0,
null,
true,
false,
globalThis,
this,
];
this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
this._goRefCounts = new Array(this._values.length).fill(Number.POSITIVE_INFINITY); // number of references that Go has to a JS value, indexed by reference id
this._ids = new Map([
// mapping from JS values to reference ids
[0, 1],
Expand All @@ -555,7 +554,7 @@ export default class Go {

const strPtr = (str) => {
const ptr = offset;
const bytes = encoder.encode(str + '\0');
const bytes = encoder.encode(`${str}\0`);
new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes);
offset += bytes.length;
if (offset % 8 !== 0) {
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler/src/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const teardown: typeof types.teardown = () => {
(globalThis as any)['@astrojs/compiler'] = undefined;
};

let getService = (): Promise<Service> => {
const getService = (): Promise<Service> => {
if (!longLivedService) {
longLivedService = startRunningService().catch((err) => {
// Let the caller try again if this fails.
Expand Down
26 changes: 15 additions & 11 deletions packages/compiler/src/node/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ import type {
TextNode,
} from '../shared/ast';

export interface Visitor {
(node: Node, parent?: ParentNode, index?: number): void | Promise<void>;
}
export type Visitor = (node: Node, parent?: ParentNode, index?: number) => void | Promise<void>;

function guard<Type extends Node>(type: string) {
return (node: Node): node is Type => node.type === type;
Expand Down Expand Up @@ -53,7 +51,7 @@ class Walker {
async visit(node: Node, parent?: ParentNode, index?: number): Promise<void> {
await this.callback(node, parent, index);
if (is.parent(node)) {
let promises = [];
const promises = [];
for (let i = 0; i < node.children.length; i++) {
const child = node.children[i];
promises.push(this.callback(child, node as ParentNode, i));
Expand Down Expand Up @@ -112,25 +110,31 @@ export function serialize(root: Node, opts: SerializeOptions = { selfClose: true
let output = '';
function visitor(node: Node) {
if (is.root(node)) {
node.children.forEach((child) => visitor(child));
for (const child of node.children) {
visitor(child);
}
} else if (is.frontmatter(node)) {
output += `---${node.value}---\n\n`;
} else if (is.comment(node)) {
output += `<!--${node.value}-->`;
} else if (is.expression(node)) {
output += `{`;
node.children.forEach((child) => visitor(child));
output += `}`;
output += '{';
for (const child of node.children) {
visitor(child);
}
output += '}';
} else if (is.literal(node)) {
output += node.value;
} else if (is.tag(node)) {
output += `<${node.name}`;
output += serializeAttributes(node);
if (node.children.length == 0 && opts.selfClose) {
output += ` />`;
if (node.children.length === 0 && opts.selfClose) {
output += ' />';
} else {
output += '>';
node.children.forEach((child) => visitor(child));
for (const child of node.children) {
visitor(child);
}
output += `</${node.name}>`;
}
}
Expand Down
Loading

0 comments on commit ead5809

Please sign in to comment.