Skip to content

Commit

Permalink
Merge pull request #471 from satanTime/issues/317
Browse files Browse the repository at this point in the history
feat: almost all ngMocks helpers support css selectors #317
  • Loading branch information
satanTime authored May 2, 2021
2 parents 8bfe681 + b348842 commit 03ec7e1
Show file tree
Hide file tree
Showing 64 changed files with 1,089 additions and 178 deletions.
1 change: 1 addition & 0 deletions docs/articles/api/ngMocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ access desired elements and instances in fixtures.
- [`faster()`](ngMocks/faster.md)
- [`throwOnConsole()`](ngMocks/throwOnConsole.md)
- [`formatHtml()`](ngMocks/formatHtml.md)
- [`formatText()`](ngMocks/formatText.md)

* [`flushTestBed()`](ngMocks/flushTestBed.md)
* [`reset()`](ngMocks/reset.md)
15 changes: 15 additions & 0 deletions docs/articles/api/ngMocks/change.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@ ngMocks.change(el, 123);
expect(component.value).toEqual(123);
```

or simply with selectors which are supported by [`ngMocks.find`](./find.md).

```ts
ngMocks.change('input', 123);
```
```ts
ngMocks.change('[data-testid="inputControl"]', 123);
```
```ts
ngMocks.change(['data-testid'], 123);
```
```ts
ngMocks.change(['data-testid', 'inputControl'], 123);
```

Profit!

It supports both `FormsModule` and `ReactiveFormsModule`.
15 changes: 15 additions & 0 deletions docs/articles/api/ngMocks/click.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,20 @@ ngMocks.click(el.nativeElement, {
});
```

or simply with selectors which are supported by [`ngMocks.find`](./find.md).

```ts
ngMocks.click('a');
```
```ts
ngMocks.click('[data-role="link"]');
```
```ts
ngMocks.click(['data-role']);
```
```ts
ngMocks.click(['data-role', 'linke']);
```

Under the hood `ngMocks.click` uses [`ngMocks.trigger`](./trigger.md),
therefore all features of [`ngMocks.trigger`](./trigger.md) can be used.
6 changes: 6 additions & 0 deletions docs/articles/api/ngMocks/crawl.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ a different amount of text nodes for the same template.
ngMocks.crawl(debugElement, callback, textNodes);
```

or simply with selectors which are supported by [`ngMocks.find`](./find.md).

```ts
ngMocks.crawl('div.root', callback, textNodes);
```

## Example: first div

A simple example, how we can find a div element.
Expand Down
11 changes: 11 additions & 0 deletions docs/articles/api/ngMocks/findInstance.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,21 @@ If the element is not specified, then the current fixture is used.
- `ngMocks.findInstance( fixture?, directive, notFoundValue? )`
- `ngMocks.findInstance( debugElement?, directive, notFoundValue? )`

or simply with selectors which are supported by [`ngMocks.find`](./find.md).

- `ngMocks.findInstance( cssSelector?, directive, notFoundValue? )`

```ts
const directive1 = ngMocks.findInstance(Directive1);
const directive2 = ngMocks.findInstance(fixture, Directive2);
const directive3 = ngMocks.findInstance(fixture.debugElement, Directive3);
const pipe = ngMocks.findInstance(fixture.debugElement, MyPipe);
const service = ngMocks.findInstance(fixture, MyService);
```

```ts
const directive1 = ngMocks.findInstance('div.node', Directive1);
const directive2 = ngMocks.findInstance(['attr'], Directive2);
const directive3 = ngMocks.findInstance(['attr', 'value'], Directive3);
const pipe = ngMocks.findInstance('div span.text', MyPipe);
```
16 changes: 16 additions & 0 deletions docs/articles/api/ngMocks/findInstances.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,26 @@ If the element is not specified, then the current fixture is used.
- `ngMocks.findInstances( fixture?, directive )`
- `ngMocks.findInstances( debugElement?, directive )`

or simply with selectors which are supported by [`ngMocks.find`](./find.md).

- `ngMocks.findInstances( cssSelector?, directive )`

```ts
const directives1 = ngMocks.findInstances(Directive1);
const directives2 = ngMocks.findInstances(fixture, Directive2);
const directives3 = ngMocks.findInstances(fixture.debugElement, Directive3);
const pipes = ngMocks.findInstances(fixture.debugElement, MyPipe);
const services = ngMocks.findInstance(fixture, MyService);
```

```ts
const directives1 = ngMocks.findInstances('div.node', Directive1);
const directives2 = ngMocks.findInstances(['attr'], Directive2);
const directives3 = ngMocks.findInstances(['attr', 'value'], Directive3);
const pipes = ngMocks.findInstances('div span.text', MyPipe);
```

:::important
A css selector helps to find the first matched element.
It will be used to look up the desired declaration.
:::
4 changes: 4 additions & 0 deletions docs/articles/api/ngMocks/findTemplateRef.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ If the element is not specified, then the current fixture is used.
- `ngMocks.findTemplateRef( debugElement?, id, notFoundValue? )`
- `ngMocks.findTemplateRef( debugElement?, [attribute, value?], notFoundValue? )`

or simply with selectors which are supported by [`ngMocks.find`](./find.md).

- `ngMocks.findTemplateRef( cssSelector?, [attribute, value?], notFoundValue? )`

## Directive

Assume, that a template has the next code.
Expand Down
4 changes: 4 additions & 0 deletions docs/articles/api/ngMocks/findTemplateRefs.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ If the element is not specified, then the current fixture is used.
- `ngMocks.findTemplateRefs( debugElement?, id )`
- `ngMocks.findTemplateRefs( debugElement?, [attribute, value?] )`

or simply with selectors which are supported by [`ngMocks.find`](./find.md).

- `ngMocks.findTemplateRefs( cssSelector?, [attribute, value?] )`

Assume, that a template has the next code.

```html
Expand Down
6 changes: 6 additions & 0 deletions docs/articles/api/ngMocks/get.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,9 @@ Returns an attribute or structural directive which belongs to the current elemen
```ts
const directive = ngMocks.get(fixture.debugElement, Directive);
```

or simply with selectors which are supported by [`ngMocks.find`](./find.md).

```ts
const directive = ngMocks.get('app-component', Directive);
```
7 changes: 7 additions & 0 deletions docs/articles/api/ngMocks/input.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ It avoids the issue of knowing the name of a component / directive the input bel

- `ngMocks.input( debugElement, input, notFoundValue? )`

or simply with selectors which are supported by [`ngMocks.find`](./find.md).

- `ngMocks.input( cssSelector, input, notFoundValue? )`

```ts
const inputValue = ngMocks.input(debugElement, 'param1');
```
```ts
const inputValue = ngMocks.input('app-component', 'param1');
```
7 changes: 7 additions & 0 deletions docs/articles/api/ngMocks/output.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ It avoids the issue of knowing the name of a component / directive the output be

- `ngMocks.output( debugElement, output, notFoundValue? )`

or simply with selectors which are supported by [`ngMocks.find`](./find.md).

- `ngMocks.output( cssSelector, output, notFoundValue? )`

```ts
const outputEmitter = ngMocks.output(debugElement, 'update');
```
```ts
const outputEmitter = ngMocks.output('app-component', 'update');
```
13 changes: 12 additions & 1 deletion docs/articles/api/ngMocks/reveal.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ ngMocks.reveal('never-possible');

## Narrowing context

`ngMocks.reveal` supports `ComponentFixture`, `DebugElements` and `DebugNodes`.
`ngMocks.reveal` supports `ComponentFixture`, `DebugElements`, `DebugNodes`
and selectors which are supported by [`ngMocks.find`](./find.md).
If none has been provided, then the latest known fixture is used.

In a template like:
Expand All @@ -83,8 +84,18 @@ const formEl = ngMocks.reveal(fixture, 'app-form');

// searches inside of formEl
const input2El = ngMocks.reveal(formEl, ['appInput']);

// searches inside of app-form
const input3El = ngMocks.reveal('app-form', ['appInput']);
```

:::important
If you use css selectors to narrow context,
then please pay attention that the first parameter is a css selector,
whereas the second one is a special selector for this helper.
Although they look the same.
:::

## Query by declaration

Returns an element which belongs to a component or directive.
Expand Down
2 changes: 1 addition & 1 deletion docs/articles/api/ngMocks/revealAll.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ we can get the form, blocks and their inputs like:
// roots
const formEl = ngMocks.reveal('app-form');
const personalEl = ngMocks.reveal(formEl, ['block', 'personal']);
const addressEl = ngMocks.reveal(formEl, ['block', 'address']);
const addressEl = ngMocks.reveal('app-form', ['block', 'address']);

// 2 elements
const personalEls = ngMocks.revealAll(personalEl, AppInputDirective);
Expand Down
8 changes: 8 additions & 0 deletions docs/articles/api/ngMocks/touch.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,12 @@ ngMocks.touch(valueAccessorEl);
expect(component.myControl.touched).toEqual(true);
```

or simply with selectors which are supported by [`ngMocks.find`](./find.md).

```ts
ngMocks.touch(['data-testid', 'inputControl']);
ngMocks.touch('input');
ngMocks.touch('[data-testid="inputControl"]');
```

Profit!
7 changes: 7 additions & 0 deletions docs/articles/api/ngMocks/trigger.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ ngMocks.trigger(el, 'mouseleave', {
});
```

or simply with selectors which are supported by [`ngMocks.find`](./find.md).

```ts
ngMocks.trigger('input[name="address"]', 'focus');
ngMocks.trigger(['name', 'address'], 'blur');
```

## Key combinations

In order to simulate shot keys and test their handlers,
Expand Down
3 changes: 2 additions & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"clsx": "1.1.1",
"postcss": "8.2.13",
"react": "17.0.2",
"react-dom": "17.0.2"
"react-dom": "17.0.2",
"react-toggle": "4.1.2"
},
"browserslist": {
"production": [
Expand Down
36 changes: 34 additions & 2 deletions e2e/am/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions libs/ng-mocks/src/lib/common/core.types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { DebugNode } from '@angular/core';
import { ComponentFixture } from '@angular/core/testing';

// It has to be an interface.
export interface AbstractType<T> extends Function {
prototype: T;
Expand All @@ -10,3 +13,12 @@ export interface Type<T> extends Function {
}

export type AnyType<T> = Type<T> | AbstractType<T>;

export type DebugNodeSelector =
| DebugNode
| ComponentFixture<any>
| string
| [string]
| [string, string | number]
| null
| undefined;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export default (value: any) => {
if (typeof value === 'string') {
return true;
}
if (Array.isArray(value) && typeof value[0] === 'string') {
return true;
}

return typeof value === 'function';
};
7 changes: 6 additions & 1 deletion libs/ng-mocks/src/lib/mock-helper/crawl/mock-helper.crawl.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { DebugNode } from '@angular/core';

import { DebugNodeSelector } from '../../common/core.types';
import mockHelperFind from '../find/mock-helper.find';
import funcGetLastFixture from '../func.get-last-fixture';

import nestedCheck from './nested-check';

export default (
el: DebugNode | undefined,
sel: DebugNode | DebugNodeSelector,
callback: (node: DebugNode) => void | boolean,
includeTextNode = false,
): void => {
const el = mockHelperFind(funcGetLastFixture(), sel, undefined);
nestedCheck(el, undefined, callback, includeTextNode);
};
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import mockHelperFind from '../find/mock-helper.find';
import funcGetLastFixture from '../func.get-last-fixture';
import funcParseFindArgs from '../func.parse-find-args';

import detectCrawler from './detect-crawler';
import detectTextNode from './detect-text-node';
import funcIsValidRevealSelector from './func.is-valid-reveal-selector';
import mockHelperCrawl from './mock-helper.crawl';

export default (...args: any[]): any[] => {
const { el, sel } = funcParseFindArgs(args);
const [el, sel] = funcParseFindArgs(args, funcIsValidRevealSelector);
const root = mockHelperFind(funcGetLastFixture(), el, undefined);

const detector = detectCrawler(sel);

const result: any[] = [];
mockHelperCrawl(el, node => {
if (node !== el && !detectTextNode(node) && detector(node)) {
mockHelperCrawl(root, node => {
if (node !== root && !detectTextNode(node) && detector(node)) {
result.push(node);
}
});
Expand Down
Loading

0 comments on commit 03ec7e1

Please sign in to comment.