From 8846e9a49e754abe2af23cc18c3dc20f5988559d Mon Sep 17 00:00:00 2001 From: Kohei Ueno Date: Tue, 17 May 2022 16:28:41 +0900 Subject: [PATCH] feat: call liff.init automatically if liff.init is called in LIFF browser (#2) --- README.md | 2 ++ src/api/init.test.ts | 41 +++++++++++++++++++++++++++++++++++++++++ src/api/init.ts | 9 ++++++++- src/plugin.test.ts | 9 ++++++--- src/plugin.ts | 5 ++++- 5 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 src/api/init.test.ts diff --git a/README.md b/README.md index 5914d17..3827fb3 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ liff.init({ mock: true, // enable mock mode }); +if (!liff.isInClient()) liff.login(); const profile = await liff.getProfile(); // { displayName: 'Brown', userId: '123456789', statusMessage: 'hello' } console.log(profile); @@ -48,6 +49,7 @@ liff.init({ mock: true, // enable mock mode }); +if (!liff.isInClient()) liff.login(); const profile = await liff.getProfile(); // { displayName: 'Brown', userId: '123456789', statusMessage: 'hello' } console.log(profile); diff --git a/src/api/init.test.ts b/src/api/init.test.ts new file mode 100644 index 0000000..ed7722f --- /dev/null +++ b/src/api/init.test.ts @@ -0,0 +1,41 @@ +import { createMockedInit } from './init'; +import { globalStore } from '../store/GlobalStore'; + +describe('mockedInit', () => { + beforeEach(() => { + globalStore.resetAll(); + }); + + it('should call injectLiffMock', async () => { + const injectLiffMock = jest.fn(); + const isInClient = false; + const mockedInit = createMockedInit(injectLiffMock, isInClient); + await mockedInit({ liffId: 'xx' }); + expect(injectLiffMock).toBeCalledTimes(1); + expect(globalStore.numberOfInitCalled).toBe(1); + expect(globalStore.numberOfLoginCalled).toBe(0); + }); + + it('should call liff.login when in LIFF Browser', async () => { + const injectLiffMock = jest.fn(); + // In LIFF Browser + const isInClient = true; + const mockedInit = createMockedInit(injectLiffMock, isInClient); + await mockedInit({ liffId: 'xx' }); + expect(injectLiffMock).toBeCalledTimes(1); + expect(globalStore.numberOfInitCalled).toBe(1); + expect(globalStore.numberOfLoginCalled).toBe(1); + }); + + it('should not call injectLiffMock and liff.login if liff.init is already called', async () => { + const injectLiffMock = jest.fn(); + const isInClient = true; + const mockedInit = createMockedInit(injectLiffMock, isInClient); + await mockedInit({ liffId: 'xx' }); + expect(injectLiffMock).toBeCalledTimes(1); + expect(globalStore.numberOfLoginCalled).toBe(1); + await mockedInit({ liffId: 'xx' }); + expect(injectLiffMock).toBeCalledTimes(1); + expect(globalStore.numberOfLoginCalled).toBe(1); + }); +}); diff --git a/src/api/init.ts b/src/api/init.ts index 23daaed..724e261 100644 --- a/src/api/init.ts +++ b/src/api/init.ts @@ -39,7 +39,8 @@ import { _removeListener } from './_removeListener'; export const createMockedInit = ( injectLiffMock: ( liff: Omit - ) => void + ) => void, + isCalledInLiffBrowser: boolean ): ActualLiff['init'] => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const init: ActualLiff['init'] = (config, successCallback, errorCallback) => { @@ -89,6 +90,12 @@ export const createMockedInit = ( globalStore.initIsCalled(); + // Login automatically if LIFF app is running in LIFF browser + // https://developers.line.biz/en/reference/liff/#login + if (isCalledInLiffBrowser && globalStore.numberOfLoginCalled === 0) { + login(); + } + if (typeof successCallback === 'function') { successCallback(); } diff --git a/src/plugin.test.ts b/src/plugin.test.ts index 2e33e5b..a59e6a8 100644 --- a/src/plugin.test.ts +++ b/src/plugin.test.ts @@ -14,13 +14,14 @@ describe('LiffMockPlugin', () => { expect(new LiffMockPlugin().name).toBe('mock'); }); - it('should call createMockedInit and getActualInitOrMockedInit, and then replace liff.init', () => { + it('should replace liff.init with mocked one', () => { const init = jest.fn(); + const isInClient = jest.fn().mockImplementation(() => false); const mockedInit = jest.fn(); _createMockedInit.mockImplementation(() => mockedInit); _getActualInitOrMockedInit.mockImplementation(() => mockedInit); - const liff = { id: 'id', init } as unknown as ActualLiff; + const liff = { id: 'id', init, isInClient } as unknown as ActualLiff; const module = new LiffMockPlugin(); module.install({ liff, hooks: {} as any }); @@ -28,12 +29,14 @@ describe('LiffMockPlugin', () => { expect(_createMockedInit).toBeCalledTimes(1); expect(_getActualInitOrMockedInit).toBeCalledTimes(1); expect(_getActualInitOrMockedInit).toBeCalledWith(init, mockedInit); + expect(isInClient).toBeCalledTimes(1); expect(liff.id).toBe('id'); // preserved expect(liff.init).toBe(mockedInit); // replaced }); it('should return module APIs, `set` and `clear`', () => { - const liff = {} as unknown as ActualLiff; + const isInClient = jest.fn().mockImplementation(() => false); + const liff = { isInClient } as unknown as ActualLiff; const module = new LiffMockPlugin(); const res = module.install({ liff, hooks: {} as any }); diff --git a/src/plugin.ts b/src/plugin.ts index f963653..85cd733 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -10,12 +10,15 @@ export class LiffMockPlugin implements LiffPlugin { install({ liff }: LiffPluginContext): LiffMockApi { const originalInit = liff.init; + const isInClient = liff.isInClient(); + const mockedInit = createMockedInit((mockedLiff) => { Object.entries(mockedLiff).forEach(([key, value]) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (liff as any)[key] = value; }); - }); + }, isInClient); + liff.init = getActualInitOrMockedInit(originalInit, mockedInit); return {