Skip to content

Commit f0e3acb

Browse files
committed
feat: pass first tests
1 parent cdc7c68 commit f0e3acb

File tree

7 files changed

+88
-23
lines changed

7 files changed

+88
-23
lines changed

src/__tests__/host-component-names.test.tsx

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import * as React from 'react';
22
import { View } from 'react-native';
33
import TestRenderer from 'react-test-renderer';
4-
import { configureInternal, getConfig } from '../config';
4+
import { configure, configureInternal, getConfig } from '../config';
55
import {
66
getHostComponentNames,
77
configureHostComponentNamesIfNeeded,
88
} from '../helpers/host-component-names';
99
import { act, render } from '..';
10+
import * as internalRenderer from '../renderer/renderer';
11+
12+
beforeEach(() => {
13+
configure({ renderer: 'internal' });
14+
});
1015

1116
describe('getHostComponentNames', () => {
1217
test('returns host component names from internal config', () => {
@@ -102,12 +107,22 @@ describe('configureHostComponentNamesIfNeeded', () => {
102107
});
103108

104109
test('throw an error when auto-detection fails', () => {
105-
const mockCreate = jest.spyOn(TestRenderer, 'create') as jest.Mock;
106-
const renderer = TestRenderer.create(<View />);
107-
108-
mockCreate.mockReturnValue({
109-
root: renderer.root,
110-
});
110+
let mockRender: jest.SpyInstance;
111+
if (getConfig().renderer === 'internal') {
112+
const result = internalRenderer.render(<View />);
113+
114+
mockRender = jest.spyOn(internalRenderer, 'render') as jest.Mock;
115+
mockRender.mockReturnValue({
116+
root: result.root,
117+
});
118+
} else {
119+
const renderer = TestRenderer.create(<View />);
120+
121+
mockRender = jest.spyOn(TestRenderer, 'create') as jest.Mock;
122+
mockRender.mockReturnValue({
123+
root: renderer.root,
124+
});
125+
}
111126

112127
expect(() => configureHostComponentNamesIfNeeded()).toThrowErrorMatchingInlineSnapshot(`
113128
"Trying to detect host component names triggered the following error:
@@ -118,6 +133,6 @@ describe('configureHostComponentNamesIfNeeded', () => {
118133
Please check if you are using compatible versions of React Native and React Native Testing Library."
119134
`);
120135

121-
mockCreate.mockReset();
136+
mockRender.mockReset();
122137
});
123138
});

src/config.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { DebugOptions } from './helpers/debug-deep';
1+
import type { DebugOptions } from './helpers/debug-deep';
2+
import type { Renderer } from './render';
23

34
/**
45
* Global configuration options for React Native Testing Library.
@@ -13,6 +14,9 @@ export type Config = {
1314

1415
/** Default options for `debug` helper. */
1516
defaultDebugOptions?: Partial<DebugOptions>;
17+
18+
/** Renderer to use for rendering components. */
19+
renderer?: Renderer;
1620
};
1721

1822
export type ConfigAliasOptions = {

src/render-act.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,27 @@
11
import TestRenderer from 'react-test-renderer';
2-
import type { ReactTestRenderer, TestRendererOptions } from 'react-test-renderer';
2+
import type { ReactTestRenderer } from 'react-test-renderer';
33
import act from './act';
4+
import { render } from './renderer/renderer';
5+
import { RenderOptions } from './render';
6+
import { getConfig } from './config';
47

58
export function renderWithAct(
69
component: React.ReactElement,
7-
options?: Partial<TestRendererOptions>,
10+
options?: RenderOptions,
811
): ReactTestRenderer {
912
let renderer: ReactTestRenderer;
1013

14+
const rendererOption = options?.renderer ?? getConfig().renderer;
15+
1116
// This will be called synchronously.
1217
void act(() => {
13-
// @ts-expect-error TestRenderer.create is not typed correctly
14-
renderer = TestRenderer.create(component, options);
18+
if (rendererOption == 'internal') {
19+
console.log(`💠 Test "${expect.getState().currentTestName}": using internal renderer`);
20+
renderer = render(component) as ReactTestRenderer;
21+
} else {
22+
// @ts-expect-error TestRenderer.create is not typed correctly
23+
renderer = TestRenderer.create(component, options);
24+
}
1525
});
1626

1727
// @ts-ignore act is synchronous, so renderer is already initialized here

src/render.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ import { renderWithAct } from './render-act';
1313
import { setRenderResult } from './screen';
1414
import { getQueriesForElement } from './within';
1515

16+
export type Renderer = 'react-test-renderer' | 'internal';
1617
export interface RenderOptions {
1718
wrapper?: React.ComponentType<any>;
1819
createNodeMock?: (element: React.ReactElement) => unknown;
1920
unstable_validateStringsRenderedWithinText?: boolean;
21+
renderer?: Renderer;
2022
}
2123

2224
export type RenderResult = ReturnType<typeof render>;
@@ -41,7 +43,7 @@ export function renderInternal<T>(
4143
wrapper: Wrapper,
4244
detectHostComponentNames = true,
4345
unstable_validateStringsRenderedWithinText,
44-
...testRendererOptions
46+
...restOptions
4547
} = options || {};
4648

4749
if (detectHostComponentNames) {
@@ -51,12 +53,12 @@ export function renderInternal<T>(
5153
if (unstable_validateStringsRenderedWithinText) {
5254
return renderWithStringValidation(component, {
5355
wrapper: Wrapper,
54-
...testRendererOptions,
56+
...restOptions,
5557
});
5658
}
5759

5860
const wrap = (element: React.ReactElement) => (Wrapper ? <Wrapper>{element}</Wrapper> : element);
59-
const renderer = renderWithAct(wrap(component), testRendererOptions);
61+
const renderer = renderWithAct(wrap(component), restOptions);
6062
return buildRenderResult(renderer, wrap);
6163
}
6264

src/renderer/host-element.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import { Container, Instance, TextInstance } from './reconciler';
33
export type HostNode = HostElement | string;
44
export type HostElementProps = Record<string, unknown>;
55

6+
type FindOptions = {
7+
deep?: boolean;
8+
};
9+
610
const instanceToHostElementMap = new WeakMap<Container | Instance, HostElement>();
711

812
export class HostElement {
@@ -58,4 +62,34 @@ export class HostElement {
5862
throw new Error(`Unexpected node type in toJSON: ${instance.tag}`);
5963
}
6064
}
65+
66+
findAll(predicate: (element: HostElement) => boolean, options?: FindOptions): HostElement[] {
67+
return findAll(this, predicate, options);
68+
}
69+
}
70+
71+
function findAll(
72+
root: HostElement,
73+
predicate: (element: HostElement) => boolean,
74+
options?: FindOptions,
75+
): HostElement[] {
76+
const deep = options?.deep ?? true;
77+
const results = [];
78+
79+
if (predicate(root)) {
80+
results.push(root);
81+
if (!deep) {
82+
return results;
83+
}
84+
}
85+
86+
root.children.forEach((child) => {
87+
if (typeof child === 'string') {
88+
return;
89+
}
90+
91+
results.push(...findAll(child, predicate, options));
92+
});
93+
94+
return results;
6195
}

src/renderer/reconciler.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ const hostConfig = {
101101
_hostContext: HostContext,
102102
internalHandle: OpaqueHandle,
103103
): Instance {
104-
console.log('createInstance', type, props);
105-
console.log('- RootContainer:', rootContainer);
106-
console.log('- HostContext:', _hostContext);
107-
console.log('- InternalHandle:', internalHandle);
104+
// console.log('createInstance', type, props);
105+
// console.log('- RootContainer:', rootContainer);
106+
// console.log('- HostContext:', _hostContext);
107+
// console.log('- InternalHandle:', internalHandle);
108108
return {
109109
tag: 'INSTANCE',
110110
type,

src/renderer/renderer.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function render(element: ReactElement): RenderResult {
3333

3434
TestReconciler.updateContainer(element, rootFiber, null, () => {
3535
// eslint-disable-next-line no-console
36-
console.log('Rendered', container?.children);
36+
//console.log('Rendered', container?.children);
3737
});
3838

3939
// update(newElement: React$Element<any>) {
@@ -50,7 +50,7 @@ export function render(element: ReactElement): RenderResult {
5050

5151
TestReconciler.updateContainer(element, rootFiber, null, () => {
5252
// eslint-disable-next-line no-console
53-
console.log('Updated', container?.children);
53+
//console.log('Updated', container?.children);
5454
});
5555
};
5656

@@ -61,7 +61,7 @@ export function render(element: ReactElement): RenderResult {
6161

6262
TestReconciler.updateContainer(null, rootFiber, null, () => {
6363
// eslint-disable-next-line no-console
64-
console.log('Unmounted', container?.children);
64+
//console.log('Unmounted', container?.children);
6565
});
6666

6767
container = null;

0 commit comments

Comments
 (0)