|
- import test from 'ava'
- import sinon from 'ts-sinon'
-
- import { remoteFunction, RpcError, RemoteError, injectRpcInfo } from '../src/index'
-
- function mockBrowser() {
- return {
- runtime: {
- sendMessage: sinon.spy(async (...args) => {}),
- },
- tabs: {
- sendMessage: sinon.spy(async (...args) => {}),
- },
- }
- }
-
- let browser = mockBrowser()
-
- test.beforeEach(() => {
- // We mock the browser globally. Note we therefore need to test serially to prevent the tests from
- // interfering with each other.
- global.browser = browser = mockBrowser()
- })
-
- test.serial('should create a function', t => {
- const remoteFunc = remoteFunction('remoteFunc', { tabId: 1 })
- t.is(remoteFunc.name, 'remoteFunc_RPC')
- t.is(typeof remoteFunc, 'function')
- })
-
- test.serial('should throw an error when unable to sendMessage', async t => {
- const remoteFunc = remoteFunction('remoteFunc', { tabId: 1 })
- browser.tabs.sendMessage = async () => { throw new Error() }
- await t.throwsAsync(remoteFunc, {
- instanceOf: RpcError,
- message: `Got no response when trying to call 'remoteFunc'. Did you enable RPC in the tab's content script?`,
- })
- })
-
- test.serial('should call the browser.tabs function when tabId is given', async t => {
- const remoteFunc = remoteFunction('remoteFunc', { tabId: 1 })
- try {
- await remoteFunc()
- } catch (e) {}
- t.true(browser.tabs.sendMessage.calledOnce)
- t.true(browser.runtime.sendMessage.notCalled)
- })
-
- test.serial('should call the browser.runtime function when tabId is undefined', async t => {
- const remoteFunc = remoteFunction('remoteFunc')
- try {
- await remoteFunc()
- } catch (e) {}
- t.true(browser.tabs.sendMessage.notCalled)
- t.true(browser.runtime.sendMessage.calledOnce)
- })
-
- test.serial('should send the call message correctly', async t => {
- const remoteFunc = remoteFunction('remoteFunc')
- try {
- await remoteFunc('a', 'b', 'c', 'd')
- } catch {}
- t.true(browser.runtime.sendMessage.calledOnce)
- t.deepEqual(browser.runtime.sendMessage.lastCall.args, [{
- __WEBEXTENSION_RPC_MESSAGE__: '__RPC_CALL__',
- funcName: 'remoteFunc',
- args: ['a', 'b', 'c', 'd'],
- addRpcInfoAsArgument: false,
- }])
- })
-
- test.serial('should handle the RpcInfoSymbol', async t => {
- const remoteFunc = remoteFunction('remoteFunc')
- try {
- await remoteFunc('a', 'b', injectRpcInfo, 'd')
- } catch {}
- t.true(browser.runtime.sendMessage.calledOnce)
- t.deepEqual(browser.runtime.sendMessage.lastCall.args, [{
- __WEBEXTENSION_RPC_MESSAGE__: '__RPC_CALL__',
- funcName: 'remoteFunc',
- args: ['a', 'b', injectRpcInfo, 'd'],
- addRpcInfoAsArgument: 2,
- }])
- })
-
- test.serial('should throw an "interfering listener" error if response is unrecognised', async t => {
- browser.tabs.sendMessage = async () => 'some unexpected return value'
- const remoteFunc = remoteFunction('remoteFunc', { tabId: 1 })
- await t.throwsAsync(remoteFunc, {
- instanceOf: RpcError,
- message: /RPC got a response from an interfering listener/,
- })
- })
-
- test.serial('should throw a "no response" error if response is undefined', async t => {
- // It seems we can get back undefined when the tab is closed before the response is sent.
- // In such cases 'no response' seems a better error message than 'interfering listener'.
- browser.tabs.sendMessage = async () => undefined
- const remoteFunc = remoteFunction('remoteFunc', { tabId: 1 })
- await t.throwsAsync(remoteFunc, {
- instanceOf: RpcError,
- message: /Got no response/,
- })
- })
-
- test.serial('should throw RemoteError if the response contains an error message', async t => {
- browser.tabs.sendMessage = async () => ({
- __WEBEXTENSION_RPC_MESSAGE__: '__RPC_RESPONSE__',
- errorMessage: 'Remote function error',
- })
- const remoteFunc = remoteFunction('remoteFunc', { tabId: 1 })
- await t.throwsAsync(remoteFunc, {
- instanceOf: RemoteError,
- message: 'Remote function error',
- })
- })
-
- test.serial('should return the value contained in the response', async t => {
- browser.tabs.sendMessage = async () => ({
- __WEBEXTENSION_RPC_MESSAGE__: '__RPC_RESPONSE__',
- returnValue: 'Remote function return value',
- })
- const remoteFunc = remoteFunction('remoteFunc', { tabId: 1 })
- t.is(await remoteFunc(), 'Remote function return value')
- })
-
- // TODO Test behaviour of executing side.
|