Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
b967206
feat(app): add new root component with assets
Hotell Feb 23, 2018
d21c055
feat(store): add ng-redux setup
Hotell Feb 23, 2018
060145d
feat(app,state): add router sync with store and refactor store
Hotell Feb 23, 2018
774bd4e
feat(products): add services
Hotell Feb 23, 2018
07a489e
feat(products): add stateles components
Hotell Feb 23, 2018
dffb4f6
feat(products): add guards
Hotell Feb 23, 2018
8f6f242
feat(products/store): add dux
Hotell Feb 23, 2018
7d4dae7
feat(products): add models
Hotell Feb 23, 2018
392b6d9
feat(products): add product-item
Hotell Feb 23, 2018
c3b2b03
feat(products): conncect products-component to store
Hotell Feb 23, 2018
d86dad3
feat(products): register entities to module
Hotell Feb 23, 2018
1580a7d
fix(store): resolve store non working drama !
Hotell Feb 23, 2018
4490e28
fix(routes): resolve router config feature module drama !
Hotell Feb 23, 2018
4e6ddee
fix(products): resolve selector correctly within product-item
Hotell Feb 23, 2018
8143729
feat(store): add router epics and register them
Hotell Feb 23, 2018
9cf7639
refactor(store): introduce epics module pattern
Hotell Feb 24, 2018
5254d33
feat(products): load pizzas via guard and epic
Hotell Feb 24, 2018
5b8fca0
feat(products/store): add other pizzas epic
Hotell Feb 24, 2018
2337d24
feat(products/store): add toppings epics and routes guards
Hotell Feb 24, 2018
f214845
feat(modules): add axios module for http
Hotell Feb 24, 2018
df8a639
refactor(products): replace httpClient with axios
Hotell Feb 24, 2018
7c881c4
style: make lines only 100 chars long
Hotell Feb 24, 2018
175c783
test: make test pass
Hotell Feb 24, 2018
0f639d7
fix: ts errors
Hotell Feb 25, 2018
0c337f3
chore: bump desp and make test run in watch mode
Hotell Feb 25, 2018
335935a
test(products): add component tests
Hotell Feb 25, 2018
f50de64
feat(products): add data-test attribute
Hotell Feb 26, 2018
712648f
e2e: add few scenarios
Hotell Feb 26, 2018
9afcc4b
feat(npm-scripts): update tasks
Hotell Feb 27, 2018
839cd39
refactor(package): rename project
Hotell Feb 27, 2018
e69b8cf
refactor(demo): move counter to demo module
Hotell Feb 27, 2018
18aefc0
feat(storybook): add module-metadata helpers and additional config
Hotell Feb 27, 2018
29d195a
feat(storybook): add pizza-itemm story
Hotell Feb 27, 2018
d385e0a
feat(modules/testing): add testbed config utility
Hotell Feb 28, 2018
ba666f3
refactor(test): use custom config for testBed to provide nicer snapshots
Hotell Feb 28, 2018
a940d31
chore: create jest snapshots issue file
Hotell Feb 28, 2018
8a8b664
ci(jest): add module mapping to @modules
Hotell Feb 28, 2018
a02d3f4
chore: bump to latest deps jest-ng prettier
Hotell Feb 28, 2018
83d01dd
chore(npm-scripts): use jest bail on verify
Hotell Mar 1, 2018
68a6d69
fix(app): exclude whole stories from app tsconfig
Hotell Mar 1, 2018
31989a5
fix(test): update jest issue test to reflect changes properly to snap…
Hotell Mar 2, 2018
9c38da0
feat(modules/testing): add possibility to override configureTest com…
Hotell Mar 2, 2018
f935903
test(demo/button): format test component template
Hotell Mar 4, 2018
40a75d4
fix(tslint): properly extends tslint with config prettier
Hotell Mar 5, 2018
df19591
feart(storybook): bump version and add addons type definitions
Hotell Mar 14, 2018
7b640cc
refactor(storybook): remove obsolete files
Hotell Mar 14, 2018
f782a91
chore: remove 3rd party example apps
Hotell Mar 14, 2018
debba7f
fix(storybook): add proper storysource webpack config
Hotell Mar 14, 2018
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
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"printWidth": 120,
"printWidth": 100,
"singleQuote": true,
"trailingComma": "es5",
"arrowParens": "always",
Expand Down
1 change: 0 additions & 1 deletion .storybook/addons.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @TODO https://github.com/storybooks/storybook/issues/3047
import '@storybook/addon-storysource/register';
import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';
Expand Down
28 changes: 12 additions & 16 deletions .storybook/config.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
import { configure } from '@storybook/angular';
import { setOptions } from '@storybook/addon-options';

import addCssWarning from './css-warnings';

// addCssWarning();

setOptions({
hierarchyRootSeparator: /\|/,
});
// automatically import all files ending in *.stories.ts
const req = require.context('../src/stories', true, /.stories.ts$/);
const reqLocal = require.context('../src/app', true, /.stories.ts$/);

function loadStories() {
// put welcome screen at the top of the list so it's the first one displayed
require('../src/stories');

// automatically import all story ts files that end with *.stories.ts
const req = require.context('../src/stories', true, /\.stories\.ts$/);
req.keys().forEach((filename) => req(filename));
req.keys().forEach(loadStory(req));
reqLocal.keys().forEach(loadStory(reqLocal));
}

// automatically import all story ts files that end with *.stories.ts within app ( side by side implementation )
const reqLocal = require.context('../src/app', true, /\.stories\.ts$/);
reqLocal.keys().forEach((filename) => reqLocal(filename));
/**
*
* @param {(filename:string)=>any} callback
*/
function loadStory(callback) {
return (filename) => callback(filename);
}

configure(loadStories, module);
13 changes: 13 additions & 0 deletions .storybook/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const path = require('path');

module.exports = (baseConfig) => {
const storysourceLoader = {
test: [/\.stories\.tsx?$/, /index\.ts$/],
loaders: [require.resolve('@storybook/addon-storysource/loader')],
include: [path.resolve(__dirname, '../src')],
enforce: 'pre',
};
baseConfig.module.rules.push(storysourceLoader);

return baseConfig;
};
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"prettier.singleQuote": true,
"prettier.semi": true,
"prettier.trailingComma": "es5",
"prettier.printWidth": 120,
"prettier.printWidth": 100,
"prettier.bracketSpacing": true,
"prettier.arrowParens": "always",
"javascript.format.enable": false,
Expand Down
107 changes: 106 additions & 1 deletion api/db.json
Original file line number Diff line number Diff line change
@@ -1 +1,106 @@
{}
{
"toppings": [
{
"id": 1,
"name": "anchovy"
},
{
"id": 2,
"name": "bacon"
},
{
"id": 3,
"name": "basil"
},
{
"id": 4,
"name": "chili"
},
{
"id": 5,
"name": "mozzarella"
},
{
"id": 6,
"name": "mushroom"
},
{
"id": 7,
"name": "olive"
},
{
"id": 8,
"name": "onion"
},
{
"id": 9,
"name": "pepper"
},
{
"id": 10,
"name": "pepperoni"
},
{
"id": 11,
"name": "sweetcorn"
},
{
"id": 12,
"name": "tomato"
}
],
"pizzas": [
{
"name": "Blazin' Inferno",
"toppings": [
{
"id": 12,
"name": "tomato"
},
{
"id": 4,
"name": "chili"
},
{
"id": 10,
"name": "pepperoni"
},
{
"id": 9,
"name": "pepper"
},
{
"id": 5,
"name": "mozzarella"
},
{
"id": 3,
"name": "basil"
},
{
"id": 8,
"name": "onion"
}
],
"id": 1
},
{
"name": "Plain Ol' Pepperoni",
"toppings": [
{
"id": 10,
"name": "pepperoni"
},
{
"id": 3,
"name": "basil"
},
{
"id": 11,
"name": "sweetcorn"
}
],
"id": 3
}
]
}
2 changes: 1 addition & 1 deletion example-apps/ngrx/api/db.json → api/initial-db.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,4 @@
"id": 3
}
]
}
}
2 changes: 1 addition & 1 deletion e2e/app.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AppPage } from './app.po';

const page = new AppPage();

fixture('ro-sa App').beforeEach(async (t) => {
fixture.skip('Pizza App').beforeEach(async (t) => {
// await waitForAngular();
});

Expand Down
53 changes: 53 additions & 0 deletions e2e/create-pizza.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { PizzaItemPage } from './pages/pizza-item.po';
import { PizzaProductsPage } from './pages/pizza-products.po';

const pizzaItem = new PizzaItemPage();
const products = new PizzaProductsPage();

const newPizzaName = 'Vikings chili pizza';

fixture
.only('Create Pizza')
.beforeEach(async (t) => {
await pizzaItem.navigateTo();
})
.afterEach(async (t) => {
const pizza = await products.getProducts(newPizzaName);
await t.click(pizza);

await t.setNativeDialogHandler((type, text, url) => {
switch (type) {
case 'confirm':
switch (text) {
case 'Are you sure?':
return true;
default:
throw new Error('Unexpected confirm dialog!');
}
case 'prompt':
return 'Hi there';
case 'alert':
throw new Error('An alert was invoked!');
}
});

await t.click(pizzaItem.form.actionButtons.delete);
});

test('should add Marvel chili Pizza to the menu!', async (t) => {
await pizzaItem.navigateToNewProduct();

await t.typeText(pizzaItem.form.pizzaNameInput, newPizzaName);

await pizzaItem.form.toppings.selectToping('chili');
await pizzaItem.form.toppings.selectToping('olive');
await pizzaItem.form.toppings.selectToping('tomato');
await pizzaItem.form.toppings.selectToping('bacon');

await t.click(pizzaItem.form.actionButtons.create);

await pizzaItem.navigateToProducts();
const pizzas = await products.getProducts();

await t.expect(pizzas.count).eql(3);
});
19 changes: 19 additions & 0 deletions e2e/pages/base.po.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Selector, t } from 'testcafe';

import { browser } from '../utils';

export class BasePage {
private mainMenu = Selector('.app__nav').find('a');
private newPizzaButton = Selector('a').withAttribute('href', '/products/new');

navigateTo(path: string = '/') {
return browser.goTo(path);
}

navigateToProducts() {
return t.click(this.mainMenu.withAttribute('href', '/products'));
}
navigateToNewProduct() {
return t.click(this.newPizzaButton);
}
}
10 changes: 10 additions & 0 deletions e2e/pages/pizza-item.po.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Selector } from 'testcafe';

import { BasePage } from './base.po';
import { PizzaFormWidget } from '../widgets/pizza-form.widget';
import { PizzaDetailWidget } from '../widgets/pizza-display.widget';

export class PizzaItemPage extends BasePage {
form = new PizzaFormWidget();
view = new PizzaDetailWidget();
}
29 changes: 29 additions & 0 deletions e2e/pages/pizza-products.po.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Selector } from 'testcafe';

import { browser } from '../utils';

import { PizzaListItem } from '../widgets/pizza-list-item.widget';

export class PizzaProductsPage {
static selector = 'app-products';
private root = Selector(PizzaProductsPage.selector);
productsListRoot = this.root.find('.products__list');
private products = new PizzaListItem();
createNewPizzaButton = Selector('.products__new > a');

async getProducts(name?: string) {
if (name) {
const pizzaName = this.products.pizzaName.withText(name);

if (pizzaName) {
return pizzaName.parent(PizzaListItem.selector);
}
return (null as any) as Selector;
}
return this.products.root;
}

navigateTo() {
return browser.goTo('/');
}
}
35 changes: 35 additions & 0 deletions e2e/pizza-list.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ClientFunction } from 'testcafe';

import { PizzaProductsPage } from './pages/pizza-products.po';

const getWindowLocation = ClientFunction(() => window.location);

const productsPage = new PizzaProductsPage();

fixture('Products showcase').beforeEach(async (t) => {
await productsPage.navigateTo();
});

test('should contain 2 pizzas', async (t) => {
const products = await productsPage.getProducts();
await t.expect(products.count).eql(2);
});

test(`should have "Blazin' Inferno" pizza on stock`, async (t) => {
const pizza = await productsPage.getProducts(`Blazin' Inferno`);
await t.expect(pizza.exists).ok();
});

test(`should not have "Black panther" pizza`, async (t) => {
const pizza = await productsPage.getProducts(`Black panther`);
await t.expect(pizza.exists).notOk();
});

test(`should navigate to Blazin Inferno detail`, async (t) => {
const pizza = await productsPage.getProducts(`Blazin' Inferno`);
await t.click(pizza);

const location: Location = await getWindowLocation();

await t.expect(location.pathname).contains('/products/1');
});
7 changes: 7 additions & 0 deletions e2e/widgets/pizza-display.widget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Selector } from 'testcafe';
export class PizzaDetailWidget {
static selector = 'pizza-display';
root = Selector(PizzaDetailWidget.selector);
pizzaImg = this.root.find('img[src="/assets/img/pizza.svg"]');
toppingsImg = this.root.find('img.pizza-display__topping');
}
19 changes: 19 additions & 0 deletions e2e/widgets/pizza-form.widget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Selector } from 'testcafe';
import { PizzaTopingsWidget } from './pizza-toppings.widget';
export class PizzaFormWidget {
static selector = 'pizza-form';
private root = Selector(PizzaFormWidget.selector);
private topingsRoot = this.root.find('.pizza-form__list');
private actionsRoot = this.root.find('.pizza-form__actions');

pizzaNameInput = this.root.find(`input[formControlName="name"]`);
pizzaNameInputError = this.root.find('.pizza-form__error');

actionButtons = {
create: this.actionsRoot.find('button').withText('Create Pizza'),
save: this.actionsRoot.find('button').withText('Save changes'),
delete: this.actionsRoot.find('button').withText('Delete Pizza'),
};

toppings = new PizzaTopingsWidget();
}
11 changes: 11 additions & 0 deletions e2e/widgets/pizza-list-item.widget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Selector } from 'testcafe';

import { PizzaDetailWidget } from './pizza-display.widget';

export class PizzaListItem {
static selector = 'pizza-item';
root = Selector(PizzaListItem.selector);
detail = new PizzaDetailWidget();
pizzaName = this.root.find('h4');
viewPizzaButton = this.root.find('button').withText('View Pizza');
}
Loading