@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
132 lines (117 loc) • 4.25 kB
text/typescript
import Transport from "@ledgerhq/hw-transport";
import { withDevice } from "./deviceAccess";
import { from, of } from "rxjs";
jest.useFakeTimers();
// Only mocks `open`
jest.mock(".", () => {
// Imports and retains the original functionalities
const originalModule = jest.requireActual(".");
return {
...originalModule,
open: jest.fn().mockReturnValue(Promise.resolve(new Transport())),
};
});
const deviceId = "test_device";
describe("withDevice", () => {
describe("When there is only 1 job", () => {
it("should provide a transport and run the given job", done => {
const job = jest.fn().mockReturnValue(of("job test result"));
withDevice(deviceId)(job).subscribe({
next: () => {
try {
expect(job).toHaveBeenCalledWith(expect.any(Transport));
done();
} catch (expectError) {
done(expectError);
}
},
error: e => done(`It should not have failed: ${JSON.stringify(e)}`),
});
});
});
describe("When a 2nd job is trying to run while another job is ongoing", () => {
describe("And the 1st job is successful", () => {
it("should run the 2 jobs sequentially", done => {
const job1Duration = 1000;
// Mocking rxjs timer is difficult -> using `setTimeout` instead of a rxjs `delay`
const job1 = jest.fn().mockReturnValue(
from(
new Promise(resolve => {
setTimeout(() => resolve("job 1 test result"), job1Duration);
}),
),
);
const job2 = jest.fn().mockReturnValue(of("job 2 test result"));
let job1_ended = false;
// Registers first the job1
withDevice(deviceId)(job1).subscribe({
next: () => {
job1_ended = true;
},
error: e => done(`It should not have failed: ${JSON.stringify(e)}`),
});
// And then job2, that should wait that job1 is finished
withDevice(deviceId)(job2).subscribe({
next: () => {
try {
// job1 should have been called before
expect(job1).toHaveBeenCalledWith(expect.any(Transport));
expect(job2).toHaveBeenCalledWith(expect.any(Transport));
done();
} catch (expectError) {
done(expectError);
}
},
error: e => done(`It should not have failed: ${JSON.stringify(e)}`),
});
// job 1 should not have started yet
expect(job1_ended).toBe(false);
// Advances job 1
jest.advanceTimersByTime(job1Duration);
});
});
describe("And the 1st job failed", () => {
it("should still run the 2 jobs sequentially", done => {
const job1Duration = 1000;
// Mocking rxjs timer is difficult -> using `setTimeout` instead of a rxjs `delay`
const job1 = jest.fn().mockReturnValue(
from(
// This time, job 1 failed
new Promise((_resolve, reject) => {
setTimeout(() => reject("job 1 failed"), job1Duration);
}),
),
);
const job2 = jest.fn().mockReturnValue(of("job 2 test result"));
let job1_ended = false;
// Registers first the job1
withDevice(deviceId)(job1).subscribe({
next: () => {
done(`Job 1 should not have succeeded`);
},
error: _e => {
job1_ended = true;
},
});
// And then job2, that should wait that job1 is finished
withDevice(deviceId)(job2).subscribe({
next: () => {
try {
// job1 should have been called before
expect(job1).toHaveBeenCalledWith(expect.any(Transport));
expect(job2).toHaveBeenCalledWith(expect.any(Transport));
done();
} catch (expectError) {
done(expectError);
}
},
error: e => done(`It should not have failed: ${JSON.stringify(e)}`),
});
// job 1 should not have started yet
expect(job1_ended).toBe(false);
// Advances job 1
jest.advanceTimersByTime(job1Duration);
});
});
});
});