Skip to content

Commit 08b119f

Browse files
committed
test: begin improving tests
1 parent bd47303 commit 08b119f

13 files changed

+1000
-1582
lines changed

.vscode/tasks.json

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"type": "npm",
6+
"script": "test:watch",
7+
"group": {
8+
"kind": "test",
9+
"isDefault": true
10+
},
11+
"problemMatcher": []
12+
}
13+
]
14+
}

package.json

+5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"start": "tsdx watch",
2020
"build": "tsup src/index.ts src/cli.ts --dts",
2121
"test": "tsdx test",
22+
"test:watch": "tsdx test --watch",
2223
"lint": "tsdx lint",
2324
"prepare": "yarn build",
2425
"clean": "rimraf dist",
@@ -35,6 +36,10 @@
3536
"singleQuote": true,
3637
"trailingComma": "es5"
3738
},
39+
"resolutions": {
40+
"**/tsdx/jest": "27.4.7",
41+
"**/tsdx/ts-jest": "27.1.3"
42+
},
3843
"devDependencies": {
3944
"@types/glob": "^7.2.0",
4045
"@types/node": "^17.0.13",

src/api.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import postcss, { Root } from 'postcss';
22

33
export interface TransformAPI {
4+
/**
5+
* Parse a raw CSS string into an abstract syntax tree and return a PostCSS `Root` node.
6+
*/
47
parse(source: string): Root;
58
}
69

src/files.ts

+9
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ export interface TransformFileInfo {
1313
source: string;
1414
}
1515

16+
/**
17+
* Construct file metadata given a file path.
18+
*/
1619
export const getFileInfo = (file: string): TransformFileInfo => {
1720
try {
1821
const source = fs.readFileSync(file, 'utf8').toString();
@@ -23,6 +26,9 @@ export const getFileInfo = (file: string): TransformFileInfo => {
2326
}
2427
};
2528

29+
/**
30+
* Write contents to the given file.
31+
*/
2632
export const writeFile = (file: string, contents: string): void => {
2733
try {
2834
fs.writeFileSync(file, contents);
@@ -31,4 +37,7 @@ export const writeFile = (file: string, contents: string): void => {
3137
}
3238
};
3339

40+
/**
41+
* Return an array of file paths that matches the given files string.
42+
*/
3443
export const getAllFilesToTransform = (files: string) => glob.sync(files);

src/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
export { traverse, Processors } from './traverse';
21
export { Transform } from './transform';

src/transform.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ export type Transform = (
2323
/**
2424
* Validate the general structure of the transform to catch simple errors.
2525
*/
26-
const validateTransform = (transform: unknown): Transform => {
27-
if (typeof transform === 'function') {
26+
export const validateTransform = (transform: unknown): Transform => {
27+
if (typeof transform === 'function' && transform.length <= 2) {
2828
return transform as Transform;
2929
} else {
3030
console.error(

src/traverse/index.ts

-33
This file was deleted.

test/api.test.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Declaration, Rule } from 'postcss';
2+
import { api } from '../src/api';
3+
4+
describe('api', () => {
5+
describe('#parse', () => {
6+
it('should return the root node of an abstract syntax tree', () => {
7+
const root = api.parse(`.class { color: orange; }`);
8+
9+
expect(root.type).toEqual('root');
10+
expect(root.nodes.length).toEqual(1);
11+
12+
const rule = root.nodes[0] as Rule;
13+
expect(rule.type).toEqual('rule');
14+
expect(rule.nodes.length).toEqual(1);
15+
16+
const declaration = rule.nodes[0] as Declaration;
17+
expect(declaration.type).toEqual('decl');
18+
expect(declaration.prop).toEqual('color');
19+
expect(declaration.value).toEqual('orange');
20+
});
21+
});
22+
});

test/examples/color-to-red.ts

-15
This file was deleted.

test/examples/uppercase-selectors.ts

-29
This file was deleted.

test/transform.test.ts

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { bundleRequire } from 'bundle-require';
2+
import { validateTransform, loadTransform, Transform } from '../src/transform';
3+
4+
jest.mock('bundle-require', () => ({ bundleRequire: jest.fn() }));
5+
6+
describe('transform', () => {
7+
let exit: jest.SpyInstance;
8+
9+
beforeEach(() => {
10+
console.error = jest.fn();
11+
exit = jest.spyOn(process, 'exit').mockImplementation();
12+
});
13+
14+
afterEach(() => {
15+
exit.mockRestore();
16+
});
17+
18+
describe('#validateTransform', () => {
19+
it('should return the transform when valid', () => {
20+
const empty: Transform = () => null;
21+
expect(validateTransform(empty)).toBe(empty);
22+
23+
const oneArg: Transform = _fileInfo => null;
24+
expect(validateTransform(oneArg)).toBe(oneArg);
25+
26+
const twoArg: Transform = (_fileInfo, _api) => null;
27+
expect(validateTransform(twoArg)).toBe(twoArg);
28+
29+
expect(console.error).not.toHaveBeenCalled();
30+
expect(exit).not.toHaveBeenCalled();
31+
});
32+
33+
it('should exit if an invalid transform is provided since there is no way to recover', () => {
34+
expect(console.error).toHaveBeenCalledTimes(0);
35+
expect(exit).toHaveBeenCalledTimes(0);
36+
37+
validateTransform(null);
38+
expect(console.error).toHaveBeenCalledTimes(1);
39+
expect(exit).toHaveBeenCalledTimes(1);
40+
41+
validateTransform(undefined);
42+
expect(console.error).toHaveBeenCalledTimes(2);
43+
expect(exit).toHaveBeenCalledTimes(2);
44+
45+
validateTransform((_fileInfo: any, _api: any, _invalid: any) => null);
46+
expect(console.error).toHaveBeenCalledTimes(3);
47+
expect(exit).toHaveBeenCalledTimes(3);
48+
});
49+
});
50+
51+
describe('#loadTransform', () => {
52+
it('should load the transform file import the "transform" export', async () => {
53+
const transform: Transform = () => null;
54+
const def: Transform = () => null;
55+
56+
(bundleRequire as jest.Mock).mockResolvedValue({
57+
mod: { transform, default: def },
58+
});
59+
60+
expect(await loadTransform('./transform.ts')).toBe(transform);
61+
expect(console.error).not.toHaveBeenCalled();
62+
expect(exit).not.toHaveBeenCalled();
63+
});
64+
65+
it('should load the transform file and fallback to the default export', async () => {
66+
const transform: Transform = () => null;
67+
68+
(bundleRequire as jest.Mock).mockResolvedValue({
69+
mod: { default: transform },
70+
});
71+
72+
expect(await loadTransform('./transform.ts')).toBe(transform);
73+
expect(console.error).not.toHaveBeenCalled();
74+
expect(exit).not.toHaveBeenCalled();
75+
});
76+
77+
it('should exit if an error occurs loading the transform file', async () => {
78+
(bundleRequire as jest.Mock).mockRejectedValue(
79+
new Error('Cannot find file.')
80+
);
81+
82+
await loadTransform('./transform.ts');
83+
expect(console.error).toHaveBeenCalledTimes(1);
84+
expect(exit).toHaveBeenCalledTimes(1);
85+
});
86+
});
87+
});

test/traverse.test.ts

-13
This file was deleted.

0 commit comments

Comments
 (0)