Skip to content
This repository has been archived by the owner on Oct 10, 2023. It is now read-only.

Commit

Permalink
Adds tests
Browse files Browse the repository at this point in the history
  • Loading branch information
saitho committed Dec 10, 2019
1 parent 3424a2d commit eb5706f
Show file tree
Hide file tree
Showing 17 changed files with 3,061 additions and 52 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
node_modules
dist
*.js
bin/amp-css
!jest.config.js
bin/amp-css
coverage
3 changes: 2 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ test/*
*.ts
tsconfig.json
*.iml
.idea
.idea
jest.config.js
12 changes: 12 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Contributing

Feel free to submit any new features via Pull Request.
Make sure the supplied tests still work and to add own test cases to cover your code.

## Running tests

Run tests by this command:

```shell script
yarn test
```
18 changes: 18 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
globals: {
'ts-jest': {
tsConfigFile: 'tsconfig.json'
}
},
moduleFileExtensions: [
'ts',
'js'
],
transform: {
'^.+\\.(ts|tsx)$': './node_modules/ts-jest/preprocessor.js'
},
testMatch: [
'**/test/**/*.test.ts'
],
testEnvironment: 'node'
};
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"prepublish": "tsc && mv ./dist/bin/amp-css.js ./dist/bin/amp-css"
"prepublish": "tsc && mv ./dist/bin/amp-css.js ./dist/bin/amp-css",
"test": "jest --forceExit --coverage --verbose"
},
"dependencies": {
"amphtml-validator": "^1.0.29",
Expand All @@ -24,8 +25,11 @@
},
"devDependencies": {
"@types/amphtml-validator": "^1.0.1",
"@types/jest": "^24.0.23",
"@types/meow": "^5.0.0",
"@types/node-sass": "^4.11.0",
"jest": "^24.9.0",
"ts-jest": "^24.2.0",
"typescript": "^3.7.3"
}
}
4 changes: 3 additions & 1 deletion src/Commands/ProcessCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ export class ProcessCommand extends AbstractCommand implements CommandInterface

// Compile file
const compileWorker = new CompileCssWorker();
compileWorker.setOptions(commandOptions);
compileWorker.setFile(commandOptions.src);
compileWorker.setMinify(commandOptions.minify);
compileWorker.setIncludePaths(commandOptions.includePath);
compileWorker.work().then(async function(css: string) {
if (commandOptions.sanitize) {
const sanitizeWorker = new SanitizeCssWorker();
Expand Down
6 changes: 6 additions & 0 deletions src/Worker/AbstractFileWorker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export abstract class AbstractFileWorker {
protected file: string;
public setFile(file: string) {
this.file = file;
}
}
53 changes: 27 additions & 26 deletions src/Worker/CompileCssWorker.ts
Original file line number Diff line number Diff line change
@@ -1,66 +1,67 @@
import {AbstractCssWorker} from "./AbstractCssWorker";
import {WorkerInterface} from "./WorkerInterface";
import {CommandOptions} from "../CommandOptions";
import * as path from "path";
import * as fs from "fs";
import * as nodeSass from 'node-sass';
import {Result, SassError} from "node-sass";
import {AbstractFileWorker} from "./AbstractFileWorker";

export class CompileCssWorker extends AbstractCssWorker implements WorkerInterface {
protected options: CommandOptions;
export class CompileCssWorker extends AbstractFileWorker implements WorkerInterface {
protected includePaths: string[] = [];
protected minify: boolean = true;

setOptions(options: CommandOptions) {
this.options = options;
setIncludePaths(includePaths: string[]) {
this.includePaths = includePaths;
}

setMinify(minify: boolean) {
this.minify = minify;
}

work(): Promise<string> {
const that = this;
const fileType = path.extname(that.options.src).replace('.', '');
const fileType = path.extname(this.file).replace('.', '');
return new Promise<string>(function (resolve, reject) {
switch (fileType) {
case 'scss':
that.compileSassToCss(that.options)
.then((css: string) => {
resolve(css);
})
that.compileSassToCss()
.then((css: string) => resolve(css))
.catch(reject);
break;
case 'css':
resolve(fs.readFileSync(that.options.src).toString());
resolve(fs.readFileSync(that.file).toString());
break;
default:
reject('Unsupported file type ' + fileType);
break;
}
});
}

protected compileSassToCss(options: CommandOptions): Promise<string> {
const includePaths: string[] = [];
if (options.hasOwnProperty('includePath')) {
includePaths.push(...options.includePath);
}
protected getScssIncludePaths(): string[] {
const includePaths = this.includePaths;
// Add folder of processed file to include paths
if (options.hasOwnProperty('src')) {
includePaths.push(path.dirname(options.src));
if (this.file !== undefined) {
includePaths.push(path.dirname(this.file));
}
return includePaths;
}

protected compileSassToCss(): Promise<string> {
var that = this;
return new Promise<string>(function(resolve, reject) {
const sassOptions: nodeSass.Options = {
includePaths: includePaths,
includePaths: that.getScssIncludePaths(),
importer: require('node-sass-tilde-importer'),
outputStyle: options.hasOwnProperty('minify') && options.minify ? 'compressed' : 'nested'
outputStyle: that.minify ? 'compressed' : 'nested',
file: that.file,
};

if (options.hasOwnProperty('src')) {
sassOptions.file = options.src;
}

nodeSass.render(sassOptions, function(err: SassError, result: Result) {
if (err) {
reject(err);
return;
}
resolve(result.css.toString());
resolve(result.css.toString().trim());
});
});
}
Expand Down
46 changes: 46 additions & 0 deletions test/Worker/AssignCssWorker.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as assert from "assert";
import DoneCallback = jest.DoneCallback;
import {CompileCssWorker} from "../../src/Worker/CompileCssWorker";
import * as path from "path";
import {AssignCssWorker} from "../../src/Worker/AssignCssWorker";

describe("AssignCssWorker", () => {
it("should assign CSS into an empty amp-custom styling tag", (done: DoneCallback) => {
const worker = new AssignCssWorker();
worker.setHtml('<style amp-custom></style>');
worker.setCss('MY-COOL-CSS');
worker.work()
.then((modifiedHTML: string) => {
assert.equal(modifiedHTML, '<style amp-custom>MY-COOL-CSS</style>');
done();
})
.catch(() => done.fail("Worker failed."));
});

it("should replace CSS in an existing amp-custom styling tag", (done: DoneCallback) => {
const worker = new AssignCssWorker();
worker.setHtml('<style amp-custom>MY-OLD-CSS</style>');
worker.setCss('MY-COOL-CSS');
worker.work()
.then((modifiedHTML: string) => {
assert.equal(modifiedHTML, '<style amp-custom>MY-COOL-CSS</style>');
done();
})
.catch(() => done.fail("Worker failed."));
});

it("should assign CSS in multiline amp-custom tag", (done: DoneCallback) => {
const worker = new AssignCssWorker();
worker.setHtml(`<style amp-custom>
</style>`);
worker.setCss('MY-COOL-CSS');
worker.work()
.then((modifiedHTML: string) => {
assert.equal(modifiedHTML, '<style amp-custom>MY-COOL-CSS</style>');
done();
})
.catch(() => done.fail("Worker failed."));
});
});
58 changes: 58 additions & 0 deletions test/Worker/CompileCssWorker.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as assert from "assert";
import DoneCallback = jest.DoneCallback;
import {CompileCssWorker} from "../../src/Worker/CompileCssWorker";
import * as path from "path";

describe("CompileCssWorker", () => {
it("should compile SCSS to CSS. minify = true", (done: DoneCallback) => {
const worker = new CompileCssWorker();
worker.setFile(path.join(__dirname, '..', 'files', 'simple-file.scss'));
worker.work()
.then((compiledCss: string) => {
assert.equal(compiledCss, 'body{color:red}');
done();
})
.catch(() => done.fail("Worker failed."));
});
it("should compile SCSS to CSS. minify = false", (done: DoneCallback) => {
const worker = new CompileCssWorker();
worker.setFile(path.join(__dirname, '..', 'files', 'simple-file.scss'));
worker.setMinify(false);
worker.work()
.then((compiledCss: string) => {
assert.equal(compiledCss, `body {
color: red; }`);
done();
})
.catch((err: string) => done.fail("Worker failed: " + err));
});
it("should compile SCSS with import to CSS", (done: DoneCallback) => {
const worker = new CompileCssWorker();
worker.setFile(path.join(__dirname, '..', 'files', 'advanced-file.scss'));
worker.work()
.then((compiledCss: string) => {
assert.equal(compiledCss, 'body{color:red}');
done();
})
.catch((error: string) => done.fail("Worker failed: " + error));
});
it("should return CSS file as is", (done: DoneCallback) => {
const worker = new CompileCssWorker();
worker.setFile(path.join(__dirname, '..', 'files', 'regular-css.css'));
worker.work()
.then((compiledCss: string) => {
assert.equal(compiledCss, `body {
color: blue;
}`);
done();
})
.catch((err: string) => done.fail("Worker failed: " + err));
});
it("should not process non-CSS and SCSS files", (done: DoneCallback) => {
const worker = new CompileCssWorker();
worker.setFile(path.join(__dirname, '..', 'files', 'some-file.html'));
worker.work()
.then(() => done.fail('Validation succeeded even though it should not!'))
.catch(() => done());
});
});
16 changes: 16 additions & 0 deletions test/Worker/SanitizeCssWorker.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {SanitizeCssWorker} from "../../src/Worker/SanitizeCssWorker";
import * as assert from "assert";
import DoneCallback = jest.DoneCallback;

describe("SanitizeCssWorker", () => {
it("should remove !important from CSS", (done: DoneCallback) => {
const worker = new SanitizeCssWorker();
worker.setCss(`body{color:red !important;}`);
worker.work()
.then((cleanedCSS: string) => {
assert.equal(cleanedCSS, 'body{color:red ;}');
done();
})
.catch(() => done.fail("Worker failed."));
});
});
47 changes: 47 additions & 0 deletions test/Worker/ValidateCssWorker.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {SanitizeCssWorker} from "../../src/Worker/SanitizeCssWorker";
import * as assert from "assert";
import DoneCallback = jest.DoneCallback;
import {ValidateCssWorker} from "../../src/Worker/ValidateCssWorker";

describe("ValidateCssWorker", () => {
it("should validate valid CSS", (done: DoneCallback) => {
const worker = new ValidateCssWorker();
worker.setCss(`body{color:red;}`);
worker.work()
.then(() => done())
.catch(() => done.fail("Validation failed."));
});
it("should fail on invalid CSS", (done: DoneCallback) => {
const worker = new ValidateCssWorker();
worker.setCss(`body{color:red !important;}`);
worker.work()
.then(() => done.fail('Validation succeeded even though it should not!'))
.catch(() => done());
});
it("should fail on too large CSS", (done: DoneCallback) => {
const fiftyByteCss = `body { font-size: 15px; border: 1px solid black; }`; // this CSS is 50 byte
let overFiftykBytesCss = '';
for (let i = 0; i < 1001; i++) {
overFiftykBytesCss = overFiftykBytesCss.concat(fiftyByteCss);
}

const worker = new ValidateCssWorker();
worker.setCss(overFiftykBytesCss);
worker.work()
.then(() => done.fail('Validation succeeded even though it should not!'))
.catch(() => done());
});
it("should succeed on CSS being exactly 50kb", (done: DoneCallback) => {
const fiftyByteCss = `body { font-size: 15px; border: 1px solid black; }`; // this CSS is 50 byte
let exactlyFiftykBytesCss = '';
for (let i = 0; i < 1000; i++) {
exactlyFiftykBytesCss = exactlyFiftykBytesCss.concat(fiftyByteCss);
}

const worker = new ValidateCssWorker();
worker.setCss(exactlyFiftykBytesCss);
worker.work()
.then(() => done())
.catch(() => done.fail("Validation failed."));
});
});
1 change: 1 addition & 0 deletions test/files/_advanced-file-variables.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$color: red;
4 changes: 4 additions & 0 deletions test/files/advanced-file.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@import "_advanced-file-variables";
body {
color: $color;
}
3 changes: 3 additions & 0 deletions test/files/regular-css.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
color: blue;
}
4 changes: 4 additions & 0 deletions test/files/simple-file.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
$color: red;
body {
color: $color;
}
Loading

0 comments on commit eb5706f

Please sign in to comment.