From fc199a8bbd67f246a4c55b0c09e2fec00de229aa Mon Sep 17 00:00:00 2001 From: Mike Ryan Date: Sat, 17 Feb 2018 15:49:55 -0600 Subject: [PATCH] build: Add Store unit tests to Bazel --- BUILD.bazel | 35 ++++++++++++++++---------- modules/store/spec/BUILD | 24 ++++++++++++++++++ modules/store/spec/edge.spec.ts | 14 ++++++----- modules/store/spec/helpers/injector.ts | 29 --------------------- modules/store/spec/integration.spec.ts | 2 +- modules/store/spec/modules.spec.ts | 17 ++++++------- modules/store/spec/selector.spec.ts | 2 +- modules/store/spec/state.spec.ts | 21 ++++++++-------- modules/store/spec/store.spec.ts | 14 ++++++----- tools/defaults.bzl | 18 +++++++++++++ tools/testing/BUILD | 8 ++++++ tools/testing/bootstrap_node_tests.ts | 33 ++++++++++++++++++++++++ 12 files changed, 142 insertions(+), 75 deletions(-) create mode 100644 modules/store/spec/BUILD delete mode 100644 modules/store/spec/helpers/injector.ts create mode 100644 tools/testing/BUILD create mode 100644 tools/testing/bootstrap_node_tests.ts diff --git a/BUILD.bazel b/BUILD.bazel index 66557dcfe2..7c8270078b 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,17 +1,26 @@ -# Marker file indicating this folder is a Bazel package. -# Needed so that tsconfig.json can be referenced from BUILD rules. +package(default_visibility = ["//visibility:public"]) +# Needed so that tsconfig.json can be referenced from BUILD rules. exports_files(["tsconfig.json"]) -# Temporary target to allow `bazel test ...` -# TODO(alexeagle): remove as soon as there is any other test in the repo -genrule( - name = "true", - outs = ["true.sh"], - cmd = "echo true > $@", -) - -sh_test( - name = "tautology_test", - srcs = [":true.sh"], +filegroup( + name = "ngrx_test_dependencies", + # NB: rxjs is not in this list, because we build it from sources using the + # label @rxjs//:rxjs + srcs = glob(["/".join([ + "node_modules", + pkg, + "**", + ext, + ]) for pkg in [ + "@angular", + "jasmine", + "jasmine-marbles", + "typescript", + "@types", + ] for ext in [ + "*.js", + "*.json", + "*.d.ts", + ]]), ) diff --git a/modules/store/spec/BUILD b/modules/store/spec/BUILD new file mode 100644 index 0000000000..556a241f61 --- /dev/null +++ b/modules/store/spec/BUILD @@ -0,0 +1,24 @@ +load("//tools:defaults.bzl", "ts_test_library", "jasmine_node_test") + +ts_test_library( + name = "test_lib", + srcs = glob( + [ + "**/*.ts", + ], + exclude = ["ngc/**/*.ts"], + ), + deps = [ + "//modules/store", + "@rxjs", + ], +) + +jasmine_node_test( + name = "test", + deps = [ + ":test_lib", + "//modules/store", + "@rxjs", + ], +) diff --git a/modules/store/spec/edge.spec.ts b/modules/store/spec/edge.spec.ts index c2e6af1261..d7a40fde3b 100644 --- a/modules/store/spec/edge.spec.ts +++ b/modules/store/spec/edge.spec.ts @@ -1,7 +1,7 @@ +import { TestBed } from '@angular/core/testing'; import { Observable } from 'rxjs/Observable'; import { todos, todoCount } from './fixtures/edge_todos'; -import { createInjector } from './helpers/injector'; -import { Store, StoreModule, select } from '../'; +import { Store, StoreModule, select } from '@ngrx/store'; interface TestAppSchema { counter1: number; @@ -21,11 +21,13 @@ describe('ngRx Store', () => { let store: Store; beforeEach(() => { - const injector = createInjector( - StoreModule.forRoot({ todos, todoCount } as any) - ); + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot({ todos, todoCount } as any), + ], + }); - store = injector.get(Store); + store = TestBed.get(Store); }); it('should provide an Observable Store', () => { diff --git a/modules/store/spec/helpers/injector.ts b/modules/store/spec/helpers/injector.ts deleted file mode 100644 index c6f0f9e4b9..0000000000 --- a/modules/store/spec/helpers/injector.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { ReflectiveInjector, ModuleWithProviders } from '@angular/core'; - -export function createInjector({ - ngModule, - providers, -}: ModuleWithProviders): ReflectiveInjector { - const injector = ReflectiveInjector.resolveAndCreate([ - ...(providers || []), - ngModule, - ]); - - injector.get(ngModule); - - return injector; -} - -export function createChildInjector( - parent: ReflectiveInjector, - { ngModule, providers }: ModuleWithProviders -): ReflectiveInjector { - const injector = parent.resolveAndCreateChild([ - ...(providers || []), - ngModule, - ]); - - injector.get(ngModule); - - return injector; -} diff --git a/modules/store/spec/integration.spec.ts b/modules/store/spec/integration.spec.ts index d50051fa64..6a9ad0cfa2 100644 --- a/modules/store/spec/integration.spec.ts +++ b/modules/store/spec/integration.spec.ts @@ -10,7 +10,7 @@ import { ActionReducer, ActionReducerMap, select, -} from '../'; +} from '@ngrx/store'; import { ReducerManager, INITIAL_STATE, State } from '../src/private_export'; import { counterReducer, diff --git a/modules/store/spec/modules.spec.ts b/modules/store/spec/modules.spec.ts index 9176787bd1..190c8b149b 100644 --- a/modules/store/spec/modules.spec.ts +++ b/modules/store/spec/modules.spec.ts @@ -7,8 +7,7 @@ import { ActionReducer, ActionReducerMap, combineReducers, -} from '../'; -import createSpy = jasmine.createSpy; +} from '@ngrx/store'; describe(`Store Modules`, () => { type RootState = { fruit: string }; @@ -48,14 +47,14 @@ describe(`Store Modules`, () => { const rootInitial = { fruit: 'orange' }; beforeEach(() => { - featureAReducerFactory = createSpy('featureAReducerFactory').and.callFake( - (rm: any, initialState?: any) => { + featureAReducerFactory = jasmine + .createSpy('featureAReducerFactory') + .and.callFake((rm: any, initialState?: any) => { return (state: any, action: any) => 4; - } - ); - rootReducerFactory = createSpy('rootReducerFactory').and.callFake( - combineReducers - ); + }); + rootReducerFactory = jasmine + .createSpy('rootReducerFactory') + .and.callFake(combineReducers); @NgModule({ imports: [ diff --git a/modules/store/spec/selector.spec.ts b/modules/store/spec/selector.spec.ts index 75fa42c7d9..59fd38452a 100644 --- a/modules/store/spec/selector.spec.ts +++ b/modules/store/spec/selector.spec.ts @@ -6,7 +6,7 @@ import { createFeatureSelector, defaultMemoize, createSelectorFactory, -} from '../'; +} from '@ngrx/store'; describe('Selectors', () => { let countOne: number; diff --git a/modules/store/spec/state.spec.ts b/modules/store/spec/state.spec.ts index 34a5821fe1..ecde28ea5e 100644 --- a/modules/store/spec/state.spec.ts +++ b/modules/store/spec/state.spec.ts @@ -1,25 +1,26 @@ import { Observable } from 'rxjs/Observable'; import { Subject } from 'rxjs/Subject'; import { ReflectiveInjector } from '@angular/core'; -import { createInjector } from './helpers/injector'; -import { StoreModule, Store, INIT } from '../'; +import { TestBed } from '@angular/core/testing'; +import { StoreModule, Store, INIT } from '@ngrx/store'; describe('ngRx State', () => { const initialState = 123; const reducer = jasmine.createSpy('reducer').and.returnValue(initialState); - let injector: ReflectiveInjector; beforeEach(() => { - injector = createInjector( - StoreModule.forRoot( - { key: reducer }, - { initialState: { key: initialState } } - ) - ); + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { key: reducer }, + { initialState: { key: initialState } } + ), + ], + }); }); it('should call the reducer to scan over the dispatcher', function() { - injector.get(Store); + TestBed.get(Store); expect(reducer).toHaveBeenCalledWith(initialState, { type: INIT, diff --git a/modules/store/spec/store.spec.ts b/modules/store/spec/store.spec.ts index 4d964ecc03..808c112944 100644 --- a/modules/store/spec/store.spec.ts +++ b/modules/store/spec/store.spec.ts @@ -1,7 +1,7 @@ import 'rxjs/add/operator/take'; import { ReflectiveInjector } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; import { hot } from 'jasmine-marbles'; -import { createInjector } from './helpers/injector'; import { ActionsSubject, ReducerManager, @@ -26,7 +26,6 @@ interface TestAppSchema { } describe('ngRx Store', () => { - let injector: ReflectiveInjector; let store: Store; let dispatcher: ActionsSubject; @@ -37,9 +36,12 @@ describe('ngRx Store', () => { counter3: counterReducer, }; - injector = createInjector(StoreModule.forRoot(reducers, { initialState })); - store = injector.get(Store); - dispatcher = injector.get(ActionsSubject); + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot(reducers, { initialState })], + }); + + store = TestBed.get(Store); + dispatcher = TestBed.get(ActionsSubject); } describe('initial state', () => { @@ -199,7 +201,7 @@ describe('ngRx Store', () => { beforeEach(() => { setup(); - const reducerManager = injector.get(ReducerManager); + const reducerManager = TestBed.get(ReducerManager); addReducerSpy = spyOn(reducerManager, 'addReducer').and.callThrough(); removeReducerSpy = spyOn( reducerManager, diff --git a/tools/defaults.bzl b/tools/defaults.bzl index 5d2a40e879..fdf88dd99f 100644 --- a/tools/defaults.bzl +++ b/tools/defaults.bzl @@ -1,5 +1,6 @@ """Re-export of some bazel rules with repository-wide defaults.""" load("@build_bazel_rules_typescript//:defs.bzl", _ts_library = "ts_library") +load("@build_bazel_rules_nodejs//:defs.bzl", _jasmine_node_test = "jasmine_node_test") def ts_library(tsconfig = None, node_modules = None, **kwargs): if not tsconfig: @@ -7,3 +8,20 @@ def ts_library(tsconfig = None, node_modules = None, **kwargs): if not node_modules: node_modules = "@ngrx_compiletime_deps//:node_modules" _ts_library(tsconfig = tsconfig, node_modules = node_modules, **kwargs) + +def ts_test_library(node_modules = None, **kwargs): + if not node_modules: + node_modules = "//:ngrx_test_dependencies" + ts_library(node_modules = node_modules, testonly = 1, **kwargs) + +def jasmine_node_test(node_modules = None, bootstrap = None, deps = [], **kwargs): + if not node_modules: + node_modules = "//:ngrx_test_dependencies" + if not bootstrap: + bootstrap = ["ngrx/tools/testing/bootstrap_node_tests.js"] + _jasmine_node_test( + bootstrap = bootstrap, + node_modules = node_modules, + deps = ["//tools/testing:node"] + deps, + **kwargs + ) diff --git a/tools/testing/BUILD b/tools/testing/BUILD new file mode 100644 index 0000000000..139acf59d7 --- /dev/null +++ b/tools/testing/BUILD @@ -0,0 +1,8 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "ts_test_library") + +ts_test_library( + name = "node", + srcs = ["bootstrap_node_tests.ts"], +) diff --git a/tools/testing/bootstrap_node_tests.ts b/tools/testing/bootstrap_node_tests.ts new file mode 100644 index 0000000000..c5b66e40b1 --- /dev/null +++ b/tools/testing/bootstrap_node_tests.ts @@ -0,0 +1,33 @@ +import 'core-js/es7/reflect'; +import 'zone.js/dist/zone-node.js'; +import 'zone.js/dist/long-stack-trace-zone.js'; +import 'zone.js/dist/proxy.js'; +import 'zone.js/dist/sync-test.js'; +import 'zone.js/dist/async-test.js'; +import 'zone.js/dist/fake-async-test.js'; + +const jasmineCore: any = require('jasmine-core'); +const patchedJasmine = jasmineCore.boot(jasmineCore); +(global as any)['jasmine'] = patchedJasmine; + +jasmineCore.boot = function() { + return patchedJasmine; +}; + +import { TestBed } from '@angular/core/testing'; +import { + ServerTestingModule, + platformServerTesting, +} from '@angular/platform-server/testing'; + +require('zone.js/dist/jasmine-patch.js'); + +const originalConfigureTestingModule = TestBed.configureTestingModule; + +TestBed.configureTestingModule = function() { + TestBed.resetTestingModule(); + + return originalConfigureTestingModule.apply(null, arguments); +}; + +TestBed.initTestEnvironment(ServerTestingModule, platformServerTesting());