|
1 |
| -import { assertSuccess, assertAnnotated } from './testHelper'; |
2 |
| -import { Replacement } from 'tslint'; |
3 |
| -import { expect } from 'chai'; |
| 1 | +import { assertAnnotated, assertMultipleAnnotated, assertSuccess } from './testHelper'; |
| 2 | +import { Rule } from '../src/templatesNoNegatedAsyncRule'; |
4 | 3 |
|
5 |
| -describe('templates-no-negated-async', () => { |
6 |
| - describe('invalid expressions', () => { |
7 |
| - it('should fail when an async pipe is negated', () => { |
8 |
| - let source = ` |
| 4 | +const { |
| 5 | + FAILURE_STRING_NEGATED_PIPE, |
| 6 | + FAILURE_STRING_UNSTRICT_EQUALITY, |
| 7 | + metadata: { ruleName } |
| 8 | +} = Rule; |
| 9 | + |
| 10 | +describe(ruleName, () => { |
| 11 | + describe('failure', () => { |
| 12 | + it('should fail if async pipe is negated', () => { |
| 13 | + const source = ` |
9 | 14 | @Component({
|
10 |
| - selector: 'foobar', |
| 15 | + selector: 'test', |
11 | 16 | template: '{{ !(foo | async) }}'
|
12 | 17 | ~~~~~~~~~~~~~~~
|
13 | 18 | })
|
14 | 19 | class Test {
|
15 |
| - constructor(public foo: Observable<Boolean>) {} |
| 20 | + constructor(foo: Observable<Boolean>) {} |
16 | 21 | }
|
17 | 22 | `;
|
18 | 23 | assertAnnotated({
|
19 |
| - ruleName: 'templates-no-negated-async', |
20 |
| - message: 'Async pipes can not be negated, use (observable | async) === false instead', |
| 24 | + message: FAILURE_STRING_NEGATED_PIPE, |
| 25 | + ruleName: ruleName, |
21 | 26 | source
|
22 | 27 | });
|
23 | 28 | });
|
24 | 29 |
|
25 |
| - it('should fail when an async pipe is including other pipes', () => { |
26 |
| - let source = ` |
| 30 | + it('should fail if async pipe is the last pipe in the negated chain', () => { |
| 31 | + const source = ` |
27 | 32 | @Component({
|
28 |
| - selector: 'foobar', |
| 33 | + selector: 'test', |
29 | 34 | template: '{{ !(foo | somethingElse | async) }}'
|
30 | 35 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
31 | 36 | })
|
32 | 37 | class Test {
|
33 |
| - constructor(public foo: Observable<Boolean>) {} |
| 38 | + constructor(foo: Observable<Boolean>) {} |
34 | 39 | }
|
35 | 40 | `;
|
36 | 41 | assertAnnotated({
|
37 |
| - ruleName: 'templates-no-negated-async', |
38 |
| - message: 'Async pipes can not be negated, use (observable | async) === false instead', |
| 42 | + message: FAILURE_STRING_NEGATED_PIPE, |
| 43 | + ruleName: ruleName, |
39 | 44 | source
|
40 | 45 | });
|
41 | 46 | });
|
42 | 47 |
|
43 |
| - it('should fail when an async pipe uses non-strict equality', () => { |
44 |
| - let source = ` |
| 48 | + it('should fail if async pipe uses unstrict equality', () => { |
| 49 | + const source = ` |
45 | 50 | @Component({
|
46 |
| - selector: 'foobar', |
| 51 | + selector: 'test', |
47 | 52 | template: '{{ (foo | async) == false }}'
|
48 | 53 | ~~~~~~~~~~~~~~~~~~~~~~
|
49 | 54 | })
|
50 | 55 | class Test {
|
51 |
| - constructor(public foo: Observable<Boolean>) {} |
| 56 | + constructor(foo: Observable<Boolean>) {} |
52 | 57 | }
|
53 | 58 | `;
|
54 | 59 | assertAnnotated({
|
55 |
| - ruleName: 'templates-no-negated-async', |
56 |
| - message: 'Async pipes must use strict equality `===` when comparing with `false`', |
| 60 | + message: FAILURE_STRING_UNSTRICT_EQUALITY, |
| 61 | + ruleName: ruleName, |
57 | 62 | source
|
58 | 63 | });
|
59 | 64 | });
|
60 | 65 |
|
61 |
| - describe('fixes', () => { |
62 |
| - it('fixes negated pipes', () => { |
63 |
| - let source = ` |
64 |
| - @Component({ |
65 |
| - selector: 'foobar', |
66 |
| - template: '{{ !(foo | async) }}' |
67 |
| - ~~~~~~~~~~~~~~~ |
68 |
| - }) |
69 |
| - class Test {} |
70 |
| - `; |
71 |
| - const failures = assertAnnotated({ |
72 |
| - ruleName: 'templates-no-negated-async', |
73 |
| - message: 'Async pipes can not be negated, use (observable | async) === false instead', |
74 |
| - source |
75 |
| - }); |
76 |
| - |
77 |
| - const res = Replacement.applyAll(source, failures[0].getFix()); |
78 |
| - expect(res).to.eq(` |
79 |
| - @Component({ |
80 |
| - selector: 'foobar', |
81 |
| - template: '{{ (foo | async) === false }}' |
82 |
| - ~~~~~~~~~~~~~~~ |
83 |
| - }) |
84 |
| - class Test {} |
85 |
| - `); |
| 66 | + it('should fail if async pipe is negated using *ngIf', () => { |
| 67 | + const source = ` |
| 68 | + @Component({ |
| 69 | + selector: 'test', |
| 70 | + template: '<div *ngIf="!(a | async)"></div>' |
| 71 | + ~~~~~~~~~~~~ |
| 72 | + }) |
| 73 | + class Test { |
| 74 | + constructor(foo: Observable<Boolean>) {} |
| 75 | + } |
| 76 | + `; |
| 77 | + assertAnnotated({ |
| 78 | + message: FAILURE_STRING_NEGATED_PIPE, |
| 79 | + ruleName: ruleName, |
| 80 | + source |
86 | 81 | });
|
| 82 | + }); |
87 | 83 |
|
88 |
| - it('fixes un-strict equality', () => { |
89 |
| - let source = ` |
90 |
| - @Component({ |
91 |
| - selector: 'foobar', |
92 |
| - template: '{{ (foo | async) == false }}' |
93 |
| - ~~~~~~~~~~~~~~~~~~~~~~ |
94 |
| - }) |
95 |
| - class Test {} |
96 |
| - `; |
97 |
| - const failures = assertAnnotated({ |
98 |
| - ruleName: 'templates-no-negated-async', |
99 |
| - message: 'Async pipes must use strict equality `===` when comparing with `false`', |
100 |
| - source |
101 |
| - }); |
| 84 | + it('should fail for multiple negated/unstrict equality async pipes', () => { |
| 85 | + const source = ` |
| 86 | + @Component({ |
| 87 | + selector: 'test', |
| 88 | + template: \` |
| 89 | + <div *ngFor="let elem of [1, 2, 3]; trackBy: trackByFn"> |
| 90 | + {{ elem }} |
| 91 | + </div> |
102 | 92 |
|
103 |
| - const res = Replacement.applyAll(source, failures[0].getFix()); |
104 |
| - expect(res).to.eq(` |
105 |
| - @Component({ |
106 |
| - selector: 'foobar', |
107 |
| - template: '{{ (foo | async) === false }}' |
108 |
| - ~~~~~~~~~~~~~~~~~~~~~~ |
109 |
| - }) |
110 |
| - class Test {} |
111 |
| - `); |
| 93 | + <div *ngIf="!(foo | async)"> |
| 94 | + ~~~~~~~~~~~~~~ |
| 95 | + {{ (foo | async) == false }} |
| 96 | + ^^^^^^^^^^^^^^^^^^^^^^ |
| 97 | + <div *ngIf="(foo | async) == false"> |
| 98 | + ##################### |
| 99 | + works! |
| 100 | + </div> |
| 101 | + </div> |
| 102 | + \` |
| 103 | + }) |
| 104 | + class Test { |
| 105 | + constructor(foo: Observable<Boolean>) {} |
| 106 | + } |
| 107 | + `; |
| 108 | + assertMultipleAnnotated({ |
| 109 | + failures: [ |
| 110 | + { |
| 111 | + char: '~', |
| 112 | + msg: FAILURE_STRING_NEGATED_PIPE |
| 113 | + }, |
| 114 | + { |
| 115 | + char: '^', |
| 116 | + msg: FAILURE_STRING_UNSTRICT_EQUALITY |
| 117 | + }, |
| 118 | + { |
| 119 | + char: '#', |
| 120 | + msg: FAILURE_STRING_UNSTRICT_EQUALITY |
| 121 | + } |
| 122 | + ], |
| 123 | + ruleName, |
| 124 | + source |
112 | 125 | });
|
113 | 126 | });
|
114 | 127 | });
|
115 | 128 |
|
116 |
| - describe('valid expressions', () => { |
117 |
| - it('should succeed if an async pipe is not negated', () => { |
118 |
| - let source = ` |
| 129 | + describe('success', () => { |
| 130 | + it('should succeed if async pipe is not negated', () => { |
| 131 | + const source = ` |
119 | 132 | @Component({
|
120 |
| - selector: 'foobar', |
| 133 | + selector: 'test', |
121 | 134 | template: '{{ (foo | async) }}'
|
122 | 135 | })
|
123 | 136 | class Test {
|
124 |
| - constructor(public foo: Observable<Boolean>) {} |
| 137 | + constructor(foo: Observable<Boolean>) {} |
125 | 138 | }
|
126 | 139 | `;
|
127 |
| - assertSuccess('templates-no-negated-async', source); |
| 140 | + assertSuccess(ruleName, source); |
128 | 141 | });
|
129 | 142 |
|
130 |
| - it('should succeed if an async pipe is not the last pipe in the negated chain', () => { |
131 |
| - let source = ` |
| 143 | + it('should succeed if async pipe is not the last pipe in the negated chain', () => { |
| 144 | + const source = ` |
132 | 145 | @Component({
|
133 |
| - selector: 'foobar', |
134 |
| - template: '{{ !(foo | async | someOtherFilter) }}' |
| 146 | + selector: 'test', |
| 147 | + template: '{{ !(foo | async | somethingElse) }}' |
135 | 148 | })
|
136 | 149 | class Test {
|
137 |
| - constructor(public foo: Observable<Boolean>) {} |
| 150 | + constructor(foo: Observable<Boolean>) {} |
138 | 151 | }
|
139 | 152 | `;
|
140 |
| - assertSuccess('templates-no-negated-async', source); |
| 153 | + assertSuccess(ruleName, source); |
141 | 154 | });
|
142 | 155 |
|
143 |
| - it('should succeed if an async pipe uses strict equality', () => { |
144 |
| - let source = ` |
| 156 | + it('should succeed if async pipe uses strict equality', () => { |
| 157 | + const source = ` |
145 | 158 | @Component({
|
146 |
| - selector: 'foobar', |
| 159 | + selector: 'test', |
147 | 160 | template: '{{ (foo | async) === false }}'
|
148 | 161 | })
|
149 | 162 | class Test {
|
150 |
| - constructor(public foo: Observable<Boolean>) {} |
| 163 | + constructor(foo: Observable<Boolean>) {} |
151 | 164 | }
|
152 | 165 | `;
|
153 |
| - assertSuccess('templates-no-negated-async', source); |
| 166 | + assertSuccess(ruleName, source); |
154 | 167 | });
|
155 | 168 |
|
156 | 169 | it('should succeed if any other pipe is negated', () => {
|
157 |
| - let source = ` |
| 170 | + const source = ` |
158 | 171 | @Component({
|
159 |
| - selector: 'foobar', |
| 172 | + selector: 'test', |
160 | 173 | template: '{{ !(foo | notAnAsyncPipe) }}'
|
161 | 174 | })
|
162 | 175 | class Test {
|
163 |
| - constructor(public foo: Observable<Boolean>) {} |
| 176 | + constructor(foo: Observable<Boolean>) {} |
164 | 177 | }
|
165 | 178 | `;
|
166 |
| - assertSuccess('templates-no-negated-async', source); |
| 179 | + assertSuccess(ruleName, source); |
167 | 180 | });
|
168 | 181 | });
|
169 | 182 | });
|
0 commit comments