/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import {render, fireEvent} from '@testing-library/react';
import {TestUtils} from 'flipper-plugin';
import {sleep} from '../../utils/sleep';
import React, {Component} from 'react';
import {
setGlobalInteractionReporter,
resetGlobalInteractionReporter,
InteractionReport,
Tracked,
wrapInteractionHandler,
describeElement,
TrackingScope,
withTrackingScope,
} from '../Tracked';
let events: InteractionReport[] = [];
beforeEach(() => {
events = [];
setGlobalInteractionReporter((e) => {
e.duration = 0; // avoid test unstability
e.totalDuration = 0;
events.push(e);
});
});
afterEach(() => {
resetGlobalInteractionReporter();
});
test('Tracked button', () => {
const rendering = render(
,
);
fireEvent.click(rendering.getByTestId('test'));
expect(events[0]).toEqual({
action: ``,
componentType: 'button',
duration: 0,
totalDuration: 0,
error: undefined,
event: 'onClick',
scope: 'Flipper',
success: 1,
});
});
test('Tracked button - custom handler', () => {
const rendering = render(
,
);
fireEvent.doubleClick(rendering.getByTestId('test'));
expect(events[0]).toEqual({
action: ``,
componentType: 'button',
duration: 0,
totalDuration: 0,
error: undefined,
event: 'onDoubleClick',
scope: 'Flipper',
success: 1,
});
});
test('Throwing action', () => {
const fn = wrapInteractionHandler(
() => {
throw new Error('Oops');
},
,
'click',
'test',
);
expect(() => {
fn();
}).toThrow('Oops');
expect(events[0]).toEqual({
action: ``,
componentType: 'button',
duration: 0,
totalDuration: 0,
error: 'Error: Oops',
event: 'click',
scope: 'test',
success: 0,
});
});
test('Async action', async () => {
const fn = wrapInteractionHandler(
async () => {
Promise.resolve(3);
},
,
'click',
'test',
);
const res = fn();
expect(typeof fn).toBe('function');
await res;
expect(events[0]).toEqual({
action: ``,
componentType: 'button',
duration: 0,
totalDuration: 0,
error: undefined,
event: 'click',
scope: 'test',
success: 1,
});
});
test('Throwing async action', async () => {
const fn = wrapInteractionHandler(
async () => {
throw new Error('Oops');
},
,
'click',
'test',
);
const res = fn();
expect(typeof fn).toBe('function');
let error = undefined;
try {
await res;
} catch (e) {
error = e;
}
expect('' + error).toBe(`Error: Oops`);
expect(events[0]).toEqual({
action: ``,
componentType: 'button',
duration: 0,
totalDuration: 0,
error: `Error: Oops`,
event: 'click',
scope: 'test',
success: 0,
});
});
test('timing', async () => {
let data: InteractionReport | undefined = undefined;
setGlobalInteractionReporter((e) => {
data = e;
});
const fn = wrapInteractionHandler(
async () => {
const start = Date.now();
while (Date.now() - start < 500) {
// nothing
}
await sleep(1000);
},
,
'click',
'test',
);
await fn();
expect(data!.duration > 100).toBe(true);
expect(data!.duration < 1000).toBe(true);
expect(data!.totalDuration > 800).toBe(true);
expect(data!.totalDuration < 2000).toBe(true);
});
test('describeElement', () => {
// String only child
expect(describeElement()).toBe('Hi!');
// title
expect(
describeElement(
,
),
).toBe('b');
// key + text
expect(describeElement()).toBe('Hi!');
// Rich JSX
expect(
describeElement(
,
),
).toBe('');
// Rich JSX with key
expect(
describeElement(
,
),
).toBe('test');
});
test('Scoped Tracked button', () => {
const rendering = render(
,
);
fireEvent.click(rendering.getByTestId('test'));
expect(events[0].scope).toEqual('outer:inner');
});
test('Scoped Tracked button in plugin', () => {
const res = TestUtils.renderPlugin({
plugin() {
return {};
},
Component() {
return (
);
},
});
fireEvent.click(res.renderer.getByTestId('test'));
expect(events[0].scope).toEqual('plugin:TestPlugin:outer:inner');
});
test('withScope - fn', () => {
const MyCoolComponent = withTrackingScope(function MyCoolComponent() {
return (
);
});
const res = TestUtils.renderPlugin({
plugin() {
return {};
},
Component() {
return ;
},
});
fireEvent.click(res.renderer.getByTestId('test'));
expect(events[0].scope).toEqual('plugin:TestPlugin:MyCoolComponent');
});
test('withScope - class', () => {
const MyCoolComponent = withTrackingScope(
class MyCoolComponent extends Component {
render() {
return (
);
}
},
);
const res = TestUtils.renderPlugin({
plugin() {
return {};
},
Component() {
return ;
},
});
fireEvent.click(res.renderer.getByTestId('test'));
expect(events[0].scope).toEqual('plugin:TestPlugin:MyCoolComponent');
});