@johnf/react-native-owl
Version:
Visual regression testing for React Native
277 lines (276 loc) • 11.8 kB
JavaScript
"use strict";
var _fs = require("fs");
var _path = _interopRequireDefault(require("path"));
var reportHelpers = _interopRequireWildcard(require("../report.js"));
var configHelpers = _interopRequireWildcard(require("./config.js"));
var run = _interopRequireWildcard(require("./run.js"));
var xcrun = _interopRequireWildcard(require("../utils/xcrun.js"));
var adb = _interopRequireWildcard(require("../utils/adb.js"));
var _execa = _interopRequireDefault(require("execa"));
var _logger = require("../logger.js");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
jest.mock('../utils/xcrun');
jest.mock('../utils/adb');
jest.spyOn(process, 'cwd').mockReturnValue('/Users/johndoe/Projects/my-project');
describe('run.ts', () => {
const mkdirMock = jest.spyOn(_fs.promises, 'mkdir');
const execKillMock = {
kill: jest.fn()
};
const execMock = jest.spyOn(_execa.default, 'command').mockImplementation();
beforeEach(() => {
mkdirMock.mockReset();
execMock.mockReset().mockReturnValue(execKillMock);
jest.clearAllMocks();
});
describe('runIOS', () => {
it('runs an iOS project', async () => {
const config = {
ios: {
workspace: 'ios/RNDemo.xcworkspace',
scheme: 'RNDemo',
configuration: 'Debug',
device: 'iPhone Simulator'
}
};
await run.runIOS(config);
expect(xcrun.xcrunStatusBar).toHaveBeenCalledTimes(1);
expect(xcrun.xcrunStatusBar).toHaveBeenCalledWith({
debug: config.debug,
device: config.ios?.device,
configuration: config.ios?.configuration,
binaryPath: config.ios?.binaryPath
});
expect(xcrun.xcrunInstall).toHaveBeenCalledTimes(1);
expect(xcrun.xcrunInstall).toHaveBeenCalledWith({
debug: config.debug,
device: config.ios?.device,
configuration: config.ios?.configuration,
binaryPath: config.ios?.binaryPath,
scheme: config.ios?.scheme
});
expect(xcrun.xcrunLaunch).toHaveBeenCalledTimes(1);
expect(xcrun.xcrunLaunch).toHaveBeenCalledWith({
debug: config.debug,
device: config.ios?.device,
configuration: config.ios?.configuration,
binaryPath: config.ios?.binaryPath,
scheme: config.ios?.scheme
});
expect(xcrun.xcrunUi).toHaveBeenCalledTimes(1);
expect(xcrun.xcrunUi).toHaveBeenCalledWith({
debug: config.debug,
device: config.ios?.device,
configuration: config.ios?.configuration,
binaryPath: config.ios?.binaryPath
});
});
});
describe('restoreIOSUI', () => {
it('cleans up an iOS project', async () => {
const logger = new _logger.Logger();
const config = {
ios: {
workspace: 'ios/RNDemo.xcworkspace',
scheme: 'RNDemo',
configuration: 'Debug',
device: 'iPhone Simulator'
}
};
await run.restoreIOSUI(config, logger);
expect(xcrun.xcrunRestore).toHaveBeenCalledTimes(1);
expect(xcrun.xcrunRestore).toHaveBeenCalledWith({
debug: config.debug,
device: config.ios?.device,
configuration: config.ios?.configuration,
binaryPath: config.ios?.binaryPath
});
});
});
describe('runAndroid', () => {
it('runs an Android project', async () => {
const config = {
android: {
packageName: 'com.rndemo',
buildType: 'Release'
}
};
await run.runAndroid(config);
expect(adb.adbInstall).toHaveBeenCalledTimes(1);
expect(adb.adbInstall).toHaveBeenCalledWith({
debug: config.debug,
buildType: config.android?.buildType,
binaryPath: config.android?.binaryPath
});
expect(adb.adbLaunch).toHaveBeenCalledTimes(1);
expect(adb.adbLaunch).toHaveBeenCalledWith({
debug: config.debug,
packageName: config.android?.packageName
});
});
});
describe('runHandler', () => {
const args = {
platform: 'ios',
config: './owl.config.json',
update: false
};
const config = {
ios: {
workspace: 'ios/RNDemo.xcworkspace',
scheme: 'RNDemo',
device: 'iPhone Simulator'
},
android: {
packageName: 'com.rndemo',
buildCommand: "echo 'Hello World'"
}
};
const expectedJestCommand = `jest --testMatch="**/?(*.)+(owl).[jt]s?(x)" --verbose --roots=${_path.default.join(process.cwd())} --runInBand`;
const commandSyncMock = jest.spyOn(_execa.default, 'commandSync');
const mockGenerateReport = jest.spyOn(reportHelpers, 'generateReport');
jest.spyOn(_logger.Logger.prototype, 'print').mockImplementation();
beforeEach(() => {
commandSyncMock.mockReset();
mockGenerateReport.mockReset();
});
it('runs an iOS project', async () => {
jest.spyOn(configHelpers, 'getConfig').mockResolvedValueOnce({
...config,
report: true
});
const mockRunIOS = jest.spyOn(run, 'runIOS').mockResolvedValueOnce();
const mockRestoreIOSUI = jest.spyOn(run, 'restoreIOSUI').mockResolvedValueOnce();
mkdirMock.mockResolvedValue(undefined);
await run.runHandler(args);
await expect(mkdirMock).toHaveBeenCalled();
await expect(mockRunIOS).toHaveBeenCalled();
await expect(commandSyncMock).toHaveBeenCalledTimes(1);
await expect(commandSyncMock).toHaveBeenCalledWith(`${expectedJestCommand} --globals='{\"OWL_CLI_ARGS\":{\"platform\":\"ios\",\"config\":\"./owl.config.json\",\"update\":false}}' --json --outputFile=/Users/johndoe/Projects/my-project/.owl/report/jest-report.json`, {
env: {
OWL_DEBUG: 'false',
OWL_IOS_SIMULATOR: 'iPhone Simulator',
OWL_PLATFORM: 'ios',
OWL_UPDATE_BASELINE: 'false'
},
stdio: 'inherit'
});
await expect(mockRestoreIOSUI).toHaveBeenCalled();
});
it('runs an Android project', async () => {
jest.spyOn(configHelpers, 'getConfig').mockResolvedValueOnce(config);
const mockRunAndroid = jest.spyOn(run, 'runAndroid').mockResolvedValueOnce();
await run.runHandler({
...args,
platform: 'android'
});
await expect(mockRunAndroid).toHaveBeenCalled();
await expect(commandSyncMock).toHaveBeenCalledTimes(1);
await expect(commandSyncMock).toHaveBeenCalledWith(`${expectedJestCommand} --globals='{\"OWL_CLI_ARGS\":{\"platform\":\"android\",\"config\":\"./owl.config.json\",\"update\":false}}'`, {
env: {
OWL_DEBUG: 'false',
OWL_IOS_SIMULATOR: 'iPhone Simulator',
OWL_PLATFORM: 'android',
OWL_UPDATE_BASELINE: 'false'
},
stdio: 'inherit'
});
});
it('runs with the update baseline flag on', async () => {
jest.spyOn(configHelpers, 'getConfig').mockResolvedValueOnce(config);
const mockRunIOS = jest.spyOn(run, 'runIOS').mockResolvedValueOnce();
await run.runHandler({
...args,
update: true
});
await expect(mockRunIOS).toHaveBeenCalled();
await expect(commandSyncMock).toHaveBeenCalledTimes(1);
await expect(commandSyncMock).toHaveBeenCalledWith(`${expectedJestCommand} --globals='{\"OWL_CLI_ARGS\":{\"platform\":\"ios\",\"config\":\"./owl.config.json\",\"update\":true}}'`, {
env: {
OWL_DEBUG: 'false',
OWL_IOS_SIMULATOR: 'iPhone Simulator',
OWL_PLATFORM: 'ios',
OWL_UPDATE_BASELINE: 'true'
},
stdio: 'inherit'
});
});
it('runs the scripts/websocket-server.js script', async () => {
jest.spyOn(configHelpers, 'getConfig').mockResolvedValueOnce(config);
await run.runHandler({
...args
});
await expect(execMock.mock.calls[0]?.[0]).toEqual('node scripts/websocket-server.js');
});
it('runs generates the report if the config is set to on', async () => {
const caseConfig = {
...config,
report: true
};
jest.spyOn(configHelpers, 'getConfig').mockResolvedValueOnce(caseConfig);
const mockRunIOS = jest.spyOn(run, 'runIOS').mockResolvedValueOnce();
commandSyncMock.mockRejectedValueOnce(undefined);
try {
await run.runHandler({
...args,
update: true
});
} catch {
await expect(mockRunIOS).toHaveBeenCalled();
await expect(commandSyncMock).toHaveBeenCalledTimes(1);
await expect(mockGenerateReport).toHaveBeenCalledTimes(1);
}
});
it('does not generate the report if the config is set to off', async () => {
const caseConfig = {
...config,
report: false
};
jest.spyOn(configHelpers, 'getConfig').mockResolvedValueOnce(caseConfig);
const mockRunIOS = jest.spyOn(run, 'runIOS').mockResolvedValueOnce();
commandSyncMock.mockRejectedValueOnce(undefined);
try {
await run.runHandler({
...args
});
} catch {
await expect(commandSyncMock).toHaveBeenCalledWith(`${expectedJestCommand} --globals='{\"OWL_CLI_ARGS\":{\"platform\":\"ios\",\"config\":\"./owl.config.json\",\"update\":false}}'`, {
env: {
OWL_DEBUG: 'false',
OWL_IOS_SIMULATOR: 'iPhone Simulator',
OWL_PLATFORM: 'ios',
OWL_UPDATE_BASELINE: 'false'
},
stdio: 'inherit'
});
await expect(mockRunIOS).toHaveBeenCalled();
await expect(commandSyncMock).toHaveBeenCalledTimes(1);
await expect(mkdirMock).not.toHaveBeenCalled();
await expect(mockGenerateReport).not.toHaveBeenCalled();
}
});
it('runs with a specific testPathPattern', async () => {
jest.spyOn(configHelpers, 'getConfig').mockResolvedValueOnce(config);
const mockRunIOS = jest.spyOn(run, 'runIOS').mockResolvedValueOnce();
const testPathPattern = '*';
await run.runHandler({
...args,
testPathPattern
});
await expect(mockRunIOS).toHaveBeenCalled();
await expect(commandSyncMock).toHaveBeenCalledTimes(1);
await expect(commandSyncMock).toHaveBeenCalledWith(`${expectedJestCommand} --globals='{\"OWL_CLI_ARGS\":{\"platform\":\"ios\",\"config\":\"./owl.config.json\",\"update\":false,\"testPathPattern\":\"${testPathPattern}\"}}' --testPathPattern="${testPathPattern}"`, expect.anything());
});
it('runs without a testPathPattern', async () => {
jest.spyOn(configHelpers, 'getConfig').mockResolvedValueOnce(config);
const mockRunIOS = jest.spyOn(run, 'runIOS').mockResolvedValueOnce();
await run.runHandler(args);
await expect(mockRunIOS).toHaveBeenCalled();
await expect(commandSyncMock).toHaveBeenCalledTimes(1);
await expect(commandSyncMock).toHaveBeenCalledWith(`${expectedJestCommand} --globals='{\"OWL_CLI_ARGS\":{\"platform\":\"ios\",\"config\":\"./owl.config.json\",\"update\":false}}'`, expect.anything());
});
});
});
//# sourceMappingURL=run.test.js.map