blob: fe25860c226fcc4a1897c02d87d5ae91be4245d8 [file] [log] [blame]
Sean Condonf4f54a12018-10-10 23:25:46 +01001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7*
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16import { TestBed, inject } from '@angular/core/testing';
17import { ActivatedRoute, Params } from '@angular/router';
18import { of } from 'rxjs';
19import * as d3 from 'd3';
20
21import { LogService } from '../log.service';
22import { FnService } from '../util/fn.service';
23
24import { ZoomService, CZ, D3S, ZoomOpts, Zoomer } from './zoom.service';
25
26class MockActivatedRoute extends ActivatedRoute {
27 constructor(params: Params) {
28 super();
29 this.queryParams = of(params);
30 }
31}
32
33
34/**
35 * ONOS GUI -- SVG -- Zoom Service - Unit Tests
36 */
37describe('ZoomService', () => {
38 let zs: ZoomService;
39 let ar: ActivatedRoute;
40 let fs: FnService;
41 let mockWindow: Window;
42 let logServiceSpy: jasmine.SpyObj<LogService>;
43
44 const svg = d3.select('body').append('svg').attr('id', 'mySvg');
45 const zoomLayer = svg.append('g').attr('id', 'myZoomlayer');
46
47 beforeEach(() => {
48 const logSpy = jasmine.createSpyObj('LogService', ['debug', 'warn', 'error']);
49 ar = new MockActivatedRoute({'debug': 'TestService'});
50 mockWindow = <any>{
51 innerWidth: 400,
52 innerHeight: 200,
53 navigator: {
54 userAgent: 'defaultUA'
55 }
56 };
57 fs = new FnService(ar, logSpy, mockWindow);
58
59 TestBed.configureTestingModule({
60 providers: [ ZoomService,
61 { provide: FnService, useValue: fs },
62 { provide: LogService, useValue: logSpy },
63 { provide: ActivatedRoute, useValue: ar },
64 { provide: 'Window', useFactory: (() => mockWindow ) }
65 ]
66 });
67
68 zs = TestBed.get(ZoomService);
69 logServiceSpy = TestBed.get(LogService);
70 });
71
72 it('should be created', () => {
73 expect(zs).toBeTruthy();
74 });
75
76 it('should define ZoomService', function () {
77 expect(zs).toBeDefined();
78 });
79
80 it('should define api functions', function () {
81 expect(fs.areFunctions(zs, [
82 'createZoomer',
83 'zoomed',
84 'adjustZoomLayer'
85 ])).toBeTruthy();
86 });
87
88 function verifyZoomerApi() {
89 expect(fs.areFunctions(zs.zoomer, [
90 'panZoom', 'reset', 'translate', 'scale', 'scaleExtent'
91 ])).toBeTruthy();
92 }
93
94 it('should fail gracefully with no option object', function () {
95 expect(() => zs.createZoomer(<ZoomOpts>{}))
96 .toThrow(new Error(CZ + 'No "svg" (svg tag)' + D3S));
97 expect(logServiceSpy.error)
98 .toHaveBeenCalledWith(CZ + 'No "svg" (svg tag)' + D3S);
99 });
100
101 it('should complain if we miss required options', function () {
102 expect(() => zs.createZoomer(<ZoomOpts>{svg: svg}))
103 .toThrow(new Error(CZ + 'No "zoomLayer" (g tag)' + D3S));
104 expect(logServiceSpy.error).toHaveBeenCalledWith(CZ + 'No "zoomLayer" (g tag)' + D3S);
105 });
106
107 it('should work with minimal parameters', function () {
108 const zoomer = zs.createZoomer(<ZoomOpts>{
109 svg: svg,
110 zoomLayer: zoomLayer
111 });
112 expect(logServiceSpy.error).not.toHaveBeenCalled();
113 verifyZoomerApi();
114 });
115
116 it('should start at scale 1 and translate 0,0', function () {
117 const zoomer = zs.createZoomer(<ZoomOpts>{
118 svg: svg,
119 zoomLayer: zoomLayer
120 });
121 verifyZoomerApi();
122 expect(zoomer.translate()).toEqual([0, 0]);
123 expect(zoomer.scale()).toEqual(1);
124 });
125
126 it('should allow programmatic pan/zoom', function () {
127 const zoomer: Zoomer = zs.createZoomer(<ZoomOpts>{
128 svg: svg,
129 zoomLayer: zoomLayer
130 });
131 verifyZoomerApi();
132
133 expect(zoomer.translate()).toEqual([0, 0]);
134 expect(zoomer.scale()).toEqual(1);
135
136 zoomer.panZoom([20, 30], 1);
137 expect(zoomer.translate()).toEqual([20, 30]);
138 expect(zoomer.scale()).toEqual(1);
139
140 zoomer.reset();
141 expect(zoomer.translate()).toEqual([0, 0]);
142 expect(zoomer.scale()).toEqual(1);
143
144
145 });
146
147 it('should provide default scale extent', function () {
148 const zoomer = zs.createZoomer(<ZoomOpts>{
149 svg: svg,
150 zoomLayer: zoomLayer
151 });
152 expect(zoomer.scaleExtent()).toEqual([0.05, 50]);
153 });
154
155 it('should allow us to override the minimum zoom', function () {
156 const zoomer = zs.createZoomer(<ZoomOpts>{
157 svg: svg,
158 zoomLayer: zoomLayer,
159 zoomMin: 1.23
160 });
161 expect(zoomer.scaleExtent()).toEqual([1.23, 50]);
162 });
163
164 it('should allow us to override the maximum zoom', function () {
165 const zoomer = zs.createZoomer(<ZoomOpts>{
166 svg: svg,
167 zoomLayer: zoomLayer,
168 zoomMax: 13
169 });
170 expect(zoomer.scaleExtent()).toEqual([0.05, 13]);
171 });
172
173 // TODO: test zoomed() where we fake out the d3.event.sourceEvent etc...
174 // need to check default enabled (true) and custom enabled predicate
175 // need to check that the callback is invoked also
176
177 it('should invoke the callback on programmatic pan/zoom', function () {
178 const foo = { cb() { return; } };
179 spyOn(foo, 'cb');
180
181 const zoomer = zs.createZoomer(<ZoomOpts>{
182 svg: svg,
183 zoomMin: 0.25,
184 zoomMax: 10,
185 zoomLayer: zoomLayer,
186 zoomEnabled: (ev) => true,
187 zoomCallback: foo.cb,
188 });
189
190 zoomer.panZoom([0, 0], 2);
191 expect(foo.cb).toHaveBeenCalled();
192 });
193});