criticizer
Version:
Linting for Angular applications, following angular.io/styleguide.
327 lines (301 loc) • 9.44 kB
text/typescript
import * as ts from 'typescript';
import * as tslint from 'tslint';
import {Ng2Walker} from '../../src/angular/ng2Walker';
import {RecursiveAngularExpressionVisitor} from '../../src/angular/templates/recursiveAngularExpressionVisitor';
import {BasicTemplateAstVisitor} from '../../src/angular/templates/basicTemplateAstVisitor';
import {BasicCssAstVisitor} from '../../src/angular/styles/basicCssAstVisitor';
import chai = require('chai');
import * as spies from 'chai-spies';
chai.use(spies);
const chaiSpy = (<any>chai).spy;
describe('ng2Walker', () => {
it('should visit components and directives', () => {
let source = `
class Baz {}
class Foobar {}
`;
let ruleArgs: tslint.IOptions = {
ruleName: 'foo',
ruleArguments: ['foo'],
disabledIntervals: null
};
let sf = ts.createSourceFile('foo', source, null);
let walker = new Ng2Walker(sf, ruleArgs);
let cmpSpy = chaiSpy.on(walker, 'visitNg2Component');
let dirSpy = chaiSpy.on(walker, 'visitNg2Directive');
walker.walk(sf);
(<any>chai.expect(cmpSpy).to.have.been).called();
(<any>chai.expect(dirSpy).to.have.been).called();
});
it('should visit inputs and outputs with args', () => {
let source = `
class Baz {
foo;
foobar;
}
`;
let ruleArgs: tslint.IOptions = {
ruleName: 'foo',
ruleArguments: ['foo'],
disabledIntervals: null
};
let sf = ts.createSourceFile('foo', source, null);
let walker = new Ng2Walker(sf, ruleArgs);
let outputsSpy = chaiSpy.on(walker, 'visitNg2Output');
let inputsSpy = chaiSpy.on(walker, 'visitNg2Input');
walker.walk(sf);
(<any>chai.expect(outputsSpy).to.have.been).called();
(<any>chai.expect(inputsSpy).to.have.been).called();
});
it('should visit component templates', () => {
let source = `
class Baz {}
`;
let ruleArgs: tslint.IOptions = {
ruleName: 'foo',
ruleArguments: ['foo'],
disabledIntervals: null
};
let sf = ts.createSourceFile('foo', source, null);
let walker = new Ng2Walker(sf, ruleArgs, {
templateVisitorCtrl: BasicTemplateAstVisitor
});
let templateSpy = chaiSpy.on(BasicTemplateAstVisitor.prototype, 'visitElement');
walker.walk(sf);
(<any>chai.expect(templateSpy).to.have.been).called();
});
it('should visit component template expressions', () => {
let source = `
class Baz {}
`;
let ruleArgs: tslint.IOptions = {
ruleName: 'foo',
ruleArguments: ['foo'],
disabledIntervals: null
};
let sf = ts.createSourceFile('foo', source, null);
let walker = new Ng2Walker(sf, ruleArgs);
let templateSpy = chaiSpy.on(RecursiveAngularExpressionVisitor.prototype, 'visitPropertyRead');
walker.walk(sf);
(<any>chai.expect(templateSpy).to.have.been).called();
});
it('should not thow when a template is not literal', () => {
let source = `
const template = '{{foo}}';
class Baz {}
`;
let ruleArgs: tslint.IOptions = {
ruleName: 'foo',
ruleArguments: ['foo'],
disabledIntervals: null
};
let sf = ts.createSourceFile('foo', source, null);
let walker = new Ng2Walker(sf, ruleArgs);
(<any>chai).expect(() => {
let templateSpy = chaiSpy.on(RecursiveAngularExpressionVisitor.prototype, 'visitPropertyRead');
walker.walk(sf);
(<any>chai.expect(templateSpy).to.not.have.been).called();
}).not.to.throw();
});
it('should not thow when a template is dynamically injected', () => {
let source = `
const template = '{{foo}}';
class Baz {}
`;
let ruleArgs: tslint.IOptions = {
ruleName: 'foo',
ruleArguments: ['foo'],
disabledIntervals: null
};
let sf = ts.createSourceFile('foo', source, null);
let walker = new Ng2Walker(sf, ruleArgs);
(<any>chai).expect(() => {
let templateSpy = chaiSpy.on(RecursiveAngularExpressionVisitor.prototype, 'visitPropertyRead');
walker.walk(sf);
(<any>chai.expect(templateSpy).to.not.have.been).called();
}).not.to.throw();
});
it('should not thow when a template is template string', () => {
let source = `
const template = '{{foo}}';
class Baz {}
`;
let ruleArgs: tslint.IOptions = {
ruleName: 'foo',
ruleArguments: ['foo'],
disabledIntervals: null
};
let sf = ts.createSourceFile('foo', source, null);
let walker = new Ng2Walker(sf, ruleArgs);
(<any>chai).expect(() => {
let templateSpy = chaiSpy.on(RecursiveAngularExpressionVisitor.prototype, 'visitPropertyRead');
walker.walk(sf);
(<any>chai.expect(templateSpy).to.not.have.been).called();
}).not.to.throw();
});
it('should ignore templateUrl', () => {
let source = `
class Baz {}
`;
let ruleArgs: tslint.IOptions = {
ruleName: 'foo',
ruleArguments: ['foo'],
disabledIntervals: null
};
let sf = ts.createSourceFile('foo', source, null);
let walker = new Ng2Walker(sf, ruleArgs);
(<any>chai).expect(() => {
let templateSpy = chaiSpy.on(RecursiveAngularExpressionVisitor.prototype, 'visitPropertyRead');
walker.walk(sf);
(<any>chai.expect(templateSpy).to.not.have.been).called();
}).not.to.throw();
});
it('should ignore empty @Component decorator', () => {
let source = `
class Baz {}
`;
let ruleArgs: tslint.IOptions = {
ruleName: 'foo',
ruleArguments: ['foo'],
disabledIntervals: null
};
let sf = ts.createSourceFile('foo', source, null);
let walker = new Ng2Walker(sf, ruleArgs);
(<any>chai).expect(() => {
let templateSpy = chaiSpy.on(RecursiveAngularExpressionVisitor.prototype, 'visitPropertyRead');
walker.walk(sf);
(<any>chai.expect(templateSpy).to.not.have.been).called();
}).not.to.throw();
});
it('should ignore non-invoked @Component decorator', () => {
let source = `
class Baz {}
`;
let ruleArgs: tslint.IOptions = {
ruleName: 'foo',
ruleArguments: ['foo'],
disabledIntervals: null
};
let sf = ts.createSourceFile('foo', source, null);
let walker = new Ng2Walker(sf, ruleArgs);
(<any>chai).expect(() => {
walker.walk(sf);
}).not.to.throw();
});
describe('inline styles', () => {
it('should not throw when there are inline styles', () => {
let source = `
class Baz {}
`;
let ruleArgs: tslint.IOptions = {
ruleName: 'foo',
ruleArguments: ['foo'],
disabledIntervals: null
};
let sf = ts.createSourceFile('foo', source, null);
let walker = new Ng2Walker(sf, ruleArgs);
(<any>chai).expect(() => {
walker.walk(sf);
}).not.to.throw();
});
it('should use the default css walker by default', () => {
let source = `
class Baz {}
`;
let ruleArgs: tslint.IOptions = {
ruleName: 'foo',
ruleArguments: ['foo'],
disabledIntervals: null
};
let sf = ts.createSourceFile('foo', source, null);
let walker = new Ng2Walker(sf, ruleArgs);
(<any>chai).expect(() => {
let templateSpy = chaiSpy.on(BasicCssAstVisitor.prototype, 'visitCssStyleSheet');
walker.walk(sf);
(<any>chai.expect(templateSpy).to.have.been).called();
}).not.to.throw();
});
it('should not break', () => {
let source = `
export class Main {
constructor() {
}
regExp() {
// complaining about missing whitespace after coma in regex
const test = /\${0,1}/.test('not important$');
console.log(test);
}
stringLiteral() {
const offset = "3";
// complaining about missing whitespace inside of string literal
const test = \`<path d="M\${offset},\${offset}">\`;
console.log(test);
}
}
// compains about missing semicolon at end
export class WantsSemiColonAtEndOfClass {
constructor() {
}
}
`;
let ruleArgs: tslint.IOptions = {
ruleName: 'foo',
ruleArguments: ['foo'],
disabledIntervals: null
};
let sf = ts.createSourceFile('foo', source, null);
let walker = new Ng2Walker(sf, ruleArgs);
(<any>chai).expect(() => {
walker.walk(sf);
}).not.to.throw();
});
});
});