Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snapshots support #24

Merged
merged 8 commits into from
Apr 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions HTMLElementPlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/

'use strict';

function escapeHTML(str) {
return str.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

const HTML_ELEMENT_REGEXP = /(HTML\w*?Element)/;
const test = isHTMLElement;

function isHTMLElement(value) {
return (
value !== undefined &&
value !== null &&
value.nodeType === 1 &&
value.constructor !== undefined &&
HTML_ELEMENT_REGEXP.test(value.constructor.name)
);
}

function printChildren(flatChildren, print, indent, colors, opts) {
return flatChildren
.map(node => {
if (typeof node === 'object') {
return print(node, print, indent, colors, opts);
} else if (typeof node === 'string') {
return colors.content.open + escapeHTML(node) + colors.content.close;
} else {
return print(node);
}
})
.join(opts.edgeSpacing);
}

function printAttributes(attributes, print, indent, colors, opts) {
return attributes
.sort()
.map(attribute => {
return (
opts.spacing +
indent(colors.prop.open + attribute.name + colors.prop.close + '=') +
colors.value.open +
`"${attribute.value}"` +
colors.value.close
);
})
.join('');
}

const print = (
element,
print,
indent,
opts,
colors
) => {
let result = colors.tag.open + '<';
const elementName = element.tagName.toLowerCase();
result += elementName + colors.tag.close;

const hasAttributes = element.attributes && element.attributes.length;
if (hasAttributes) {
const attributes = Array.prototype.slice.call(element.attributes);
result += printAttributes(attributes, print, indent, colors, opts);
}

const flatChildren = Array.prototype.slice.call(element.children);
if (!flatChildren.length && element.textContent) {
flatChildren.push(element.textContent.trim());
}

const closeInNewLine = hasAttributes && !opts.min;
if (flatChildren.length) {
const children = printChildren(flatChildren, print, indent, colors, opts);
result +=
colors.tag.open +
(closeInNewLine ? '\n' : '') +
'>' +
colors.tag.close +
(children && opts.edgeSpacing + indent(children) + opts.edgeSpacing) +
colors.tag.open +
'</' +
elementName +
'>' +
colors.tag.close;
} else {
result +=
colors.tag.open + (closeInNewLine ? '\n' : ' ') + '/>' + colors.tag.close;
}

return result;
};

module.exports = ({print, test});
64 changes: 64 additions & 0 deletions angular-snapshot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
const printAttributes = (val, attributes, print, indent, colors, opts) => {
return attributes
.sort()
.map(attribute => {
return (
opts.spacing +
indent(colors.prop.open + attribute + colors.prop.close + '=') +
colors.value.open +
(val.componentInstance[attribute] &&
val.componentInstance[attribute].constructor
? '{[Function ' +
val.componentInstance[attribute].constructor.name +
']}'
: `"${val.componentInstance[attribute]}"`) +
colors.value.close
);
})
.join('');
};

const print = (val, print, indent, opts, colors) => {
let result = '';
let componentAttrs = '';

const componentName = val.componentRef._elDef.element.name;
const componentInstance = print(val.componentInstance);
const nodes = val.componentRef._view.nodes
.filter(node => node.hasOwnProperty('renderElement'))
.map(node => print(node.renderElement))
.join('\n');

const attributes = Object.keys(val.componentInstance);

if (attributes.length) {
componentAttrs += printAttributes(
val,
attributes,
print,
indent,
colors,
opts
);
}

return (
'<' +
componentName +
componentAttrs +
(componentAttrs.length ? '\n' : '') +
'>\n' +
indent(nodes) +
'\n</' +
componentName +
'>'
);
};

const test = val =>
val !== undefined &&
val !== null &&
typeof val === 'object' &&
Object.prototype.hasOwnProperty.call(val, 'componentRef');

module.exports = {print, test};
4 changes: 2 additions & 2 deletions circle.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
machine:
environment:
YARN_VERSION: 0.20.3
YARN_VERSION: 0.22.0
PATH: "${PATH}:${HOME}/.yarn/bin:${HOME}/${CIRCLE_PROJECT_REPONAME}/node_modules/.bin"
node:
version: 7
Expand All @@ -20,4 +20,4 @@ dependencies:
test:
override:
- yarn run test:ci
- yarn link && cd example && yarn run test:ci && yarn run test:coverage
- yarn link && cd example && yarn link jest-preset-angular && yarn run test:ci && yarn run test:coverage
17 changes: 17 additions & 0 deletions example/src/app/__snapshots__/app.component.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`AppComponent snaps 1`] = `
<app-root
hasClass={[Function Boolean]}
title={[Function String]}
>
<div
id="root1"
ng-version="4.0.1"
>
<h1>
<app-calc />
</h1>
</div>
</app-root>
`;
3 changes: 3 additions & 0 deletions example/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<h1>
{{title}}
<app-calc
[hasAClass]="hasClass"
></app-calc>
</h1>
9 changes: 8 additions & 1 deletion example/src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { TestBed, async } from '@angular/core/testing';

import { NO_ERRORS_SCHEMA } from '@angular/core';
import { CalcComponent } from 'app/calc/calc.component';
import { AppComponent } from './app.component';

describe('AppComponent', () => {
Expand All @@ -8,6 +9,7 @@ describe('AppComponent', () => {
declarations: [
AppComponent
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
}));

Expand All @@ -17,6 +19,11 @@ describe('AppComponent', () => {
expect(app).toBeTruthy();
}));

it('snaps', () => {
const fixture = TestBed.createComponent(AppComponent);
expect(fixture).toMatchSnapshot();
})

it(`should have as title 'app works!'`, async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
Expand Down
1 change: 1 addition & 0 deletions example/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ import { Component } from '@angular/core';
})
export class AppComponent {
title = 'app works!';
hasClass = true;
}
20 changes: 20 additions & 0 deletions example/src/app/calc/__snapshots__/calc.component.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`CalcComponent should snap 1`] = `
<app-calc
prop1={[Function Number]}
>
<div
id="root0"
ng-version="4.0.1"
>
<p
class="a-default-class"
ng-reflect-klass="a-default-class"
ng-reflect-ng-class="[object Object]"
>
calc works!
</p>
</div>
</app-calc>
`;
7 changes: 6 additions & 1 deletion example/src/app/calc/calc.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
<p>
<p
class="a-default-class"
[ngClass]="{
'a-class': hasAClass
}"
>
calc works!
</p>
8 changes: 4 additions & 4 deletions example/src/app/calc/calc.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ describe('CalcComponent', () => {

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CalcComponent ]
declarations: [CalcComponent]
})
.compileComponents();
.compileComponents();
}));

beforeEach(() => {
Expand All @@ -19,7 +19,7 @@ describe('CalcComponent', () => {
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
it('should snap', () => {
expect(fixture).toMatchSnapshot();
});
});
14 changes: 12 additions & 2 deletions example/src/app/calc/calc.component.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, Input } from '@angular/core';
import { Observable } from 'rxjs/Observable';

@Component({
selector: 'app-calc',
templateUrl: './calc.component.html',
styleUrls: ['./calc.component.css']
})
export class CalcComponent implements OnInit {
@Input() hasAClass;
prop1: number;
observable$: Observable<string>;

constructor() { }
constructor() {
this.init();
this.prop1 = 1337;
}

ngOnInit() {
}

init() {
return 'Imma method';
}
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
"jest": "^19.0.2",
"typescript": "^2.2.2"
},
"peerDependencies": {
"jest": "^19.0.2"
},
"scripts": {
"test": "jest",
"test:ci": "jest -i"
Expand Down
5 changes: 5 additions & 0 deletions setupJest.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ require('zone.js/dist/sync-test');
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');
require('jest-zone-patch');
const angularSnapshot = require('./angular-snapshot');
const HTMLElementPlugin = require('./HTMLElementPlugin');
const { getTestBed } = require('@angular/core/testing');
const {
BrowserDynamicTestingModule,
Expand All @@ -16,3 +18,6 @@ getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);

expect.addSnapshotSerializer(HTMLElementPlugin);
expect.addSnapshotSerializer(angularSnapshot);