Skip to content

Commit

Permalink
Merge pull request #88 from Telegram-Web-Apps/feature/restore-compone…
Browse files Browse the repository at this point in the history
…nts-state

Feature/restore components state
  • Loading branch information
heyqbnk authored Sep 15, 2023
2 parents 9a1e3f3 + 0bacb66 commit 93e3eb2
Show file tree
Hide file tree
Showing 218 changed files with 5,554 additions and 2,655 deletions.
6 changes: 6 additions & 0 deletions .changeset/beige-chefs-jam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@twa.js/sdk-react": minor
"@twa.js/sdk-solid": minor
---

Implement CloudStorage utilities
5 changes: 5 additions & 0 deletions .changeset/dirty-rats-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@twa.js/bridge": minor
---

Implement new method - request. It allows calling specified methods and capturing specified events.
5 changes: 5 additions & 0 deletions .changeset/eleven-vans-act.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@twa.js/utils": patch
---

Move some utilities related to colors, events handling and some types to separate packages
6 changes: 6 additions & 0 deletions .changeset/pretty-birds-divide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"eslint-config-custom": minor
"jest-config-custom": minor
---

Add new rules to eslint config. Jest config now uses babel-jest
8 changes: 8 additions & 0 deletions .changeset/tidy-queens-fly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@twa.js/event-emitter": patch
"@twa.js/util-types": patch
"@twa.js/parsing": patch
"@twa.js/colors": patch
---

Release package.
5 changes: 5 additions & 0 deletions .changeset/tough-zebras-kiss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@twa.js/init-data": patch
---

Switch to new package parsing utilities
5 changes: 5 additions & 0 deletions .changeset/witty-starfishes-complain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@twa.js/sdk": minor
---

Implement new CloudStorage component. Implement 6.9 methods. Make components restore from the session storage.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"rollup-preset-solid": "^2.0.1",
"ts-jest": "^29.1.1",
"tslib": "^2.6.0",
"turbo": "^1.9.7",
"turbo": "^1.10.14",
"typescript": "^5.1.6"
},
"packageManager": "[email protected]",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface DomEmitter {
/**
* Removes simple emitter, which could be used in tests.
*/
export function domEmitter(): DomEmitter {
export function createDomEmitter(): DomEmitter {
const listeners: Record<string, ((...args: any) => any)[]> = {};

return {
Expand All @@ -21,10 +21,5 @@ export function domEmitter(): DomEmitter {
const cbs = listeners[event.type] || [];
cbs.forEach((cb) => cb(event));
},
// removeAllListeners: () => {
// Object.keys(listeners).forEach((event) => {
// delete listeners[event];
// });
// },
};
}
59 changes: 59 additions & 0 deletions packages/bridge/__tests__/__utils__/createWindow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { createDomEmitter } from './createDomEmitter.js';

interface CreateWindowOptions {
innerWidth?: number;
innerHeight?: number;
env?: 'iframe';
}

export type WindowSpy = jest.SpyInstance<Window & typeof globalThis>;

/**
* Mocks window and returns created spy.
* @param options - additional options.
*/
export function createWindow(options: CreateWindowOptions = {}): WindowSpy {
const { innerWidth, innerHeight, env } = options;
const postMessageSpy = jest.fn();
const wnd = {
innerHeight,
innerWidth,
...createDomEmitter(),
...(env === 'iframe' ? {
top: 1,
self: 2,
parent: { postMessage: postMessageSpy },
} : {}),
};

return jest.spyOn(window, 'window', 'get').mockImplementation(() => wnd as any);
}

// export function mockWindow(
// options: MockWindowOptions = {},
// ): jest.SpyInstance<Window & typeof globalThis> {
// const { innerWidth, innerHeight, env } = options;
// const spy = jest.spyOn(window, 'window', 'get');
// const postMessageSpy = jest.fn();
//
// beforeEach(() => {
// const wnd = {
// innerHeight,
// innerWidth,
// ...createDomEmitter(),
// ...(env === 'iframe' ? {
// top: 1,
// self: 2,
// parent: { postMessage: postMessageSpy },
// } : {}),
// };
// spy.mockImplementation(() => wnd as any);
// });
//
// afterEach(() => {
// postMessageSpy.mockReset();
// spy.mockReset();
// });
//
// return spy;
// }
11 changes: 11 additions & 0 deletions packages/bridge/__tests__/__utils__/dispatchWindowMessageEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Uses window.dispatchEvent function with specified message event
* to dispatch event to imitate its creation by Telegram.
* @param eventType - event name.
* @param eventData - event payload.
*/
export function dispatchWindowMessageEvent(eventType: string, eventData?: unknown): void {
window.dispatchEvent(new MessageEvent('message', {
data: JSON.stringify({ eventType, eventData }),
}));
}
38 changes: 0 additions & 38 deletions packages/bridge/__tests__/__utils__/window.ts

This file was deleted.

21 changes: 11 additions & 10 deletions packages/bridge/__tests__/env.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
import { hasExternalNotify, hasWebviewProxy, isIframe } from '../src/index.js';
import { hasExternalNotify, hasWebviewProxy, isIframe } from '../src/env.js';

const windowSpy = jest.spyOn(window, 'window', 'get');
const emptyFunction = () => {
};

afterEach(() => {
jest.resetAllMocks();
});

afterAll(() => {
jest.restoreAllMocks();
});

describe('env.ts', () => {
describe('hasExternalNotify', () => {
it('should return true if passed object contains path property "external.notify" and "notify" is a function property.', () => {
Expand All @@ -32,6 +23,16 @@ describe('env.ts', () => {
});

describe('isIframe', () => {
const windowSpy = jest.spyOn(window, 'window', 'get');

afterEach(() => {
windowSpy.mockReset();
});

afterAll(() => {
windowSpy.mockRestore();
});

it('should return true in case window.self !== window.top. Otherwise, false.', () => {
windowSpy.mockImplementation(() => ({ self: 900, top: 1000 }) as any);
expect(isIframe()).toBe(true);
Expand Down
28 changes: 19 additions & 9 deletions packages/bridge/__tests__/events/emitter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { createEmitter, singletonEmitter } from '../../src/events/emitter.js';
import { dispatchWindowEvent, mockWindow } from '../__utils__/window.js';
import { createWindow, type WindowSpy } from '../__utils__/createWindow.js';
import { dispatchWindowMessageEvent } from '../__utils__/dispatchWindowMessageEvent.js';

import type { EventName, EventParams } from '../../src/index.js';

type TestCase<E extends EventName> =
Expand All @@ -12,9 +14,17 @@ type TestCases = {
: [Event, TestCase<Event> | TestCase<Event>[]];
}[EventName][];

mockWindow({
innerWidth: 1920,
innerHeight: 1080,
let windowSpy: WindowSpy;

beforeEach(() => {
windowSpy = createWindow({
innerWidth: 1920,
innerHeight: 1080,
});
});

afterEach(() => {
windowSpy.mockReset();
});

describe('events', () => {
Expand Down Expand Up @@ -94,29 +104,29 @@ describe('events', () => {

// No expected data to be passed to listener.
if (inputOrCaseOrCases === undefined) {
dispatchWindowEvent(event);
dispatchWindowMessageEvent(event);
expect(spy).toBeCalledWith();
return;
}

// Input is equal to expected result.
if (!Array.isArray(inputOrCaseOrCases)) {
dispatchWindowEvent(event, inputOrCaseOrCases);
dispatchWindowMessageEvent(event, inputOrCaseOrCases);
expect(spy).toBeCalledWith(inputOrCaseOrCases);
return;
}

// Input differs from expected result.
if (!Array.isArray(inputOrCaseOrCases[0])) {
const [input, expected] = inputOrCaseOrCases;
dispatchWindowEvent(event, input);
dispatchWindowMessageEvent(event, input);
expect(spy).toBeCalledWith(expected);
return;
}

// List of cases.
inputOrCaseOrCases.forEach(([input, expected = input]) => {
dispatchWindowEvent(event, input);
dispatchWindowMessageEvent(event, input);
expect(spy).toBeCalledWith(expected);
});
});
Expand All @@ -128,7 +138,7 @@ describe('events', () => {

emitter.on('viewport_changed', spy);

dispatchWindowEvent('viewport_changed', 'broken data');
dispatchWindowMessageEvent('viewport_changed', 'broken data');

expect(spy).not.toBeCalled();
});
Expand Down
15 changes: 12 additions & 3 deletions packages/bridge/__tests__/events/off.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import { on, off } from '../../src/index.js';
import { dispatchWindowEvent, mockWindow } from '../__utils__/window.js';
import { createWindow, type WindowSpy } from '../__utils__/createWindow.js';
import { dispatchWindowMessageEvent } from '../__utils__/dispatchWindowMessageEvent.js';

mockWindow();
let windowSpy: WindowSpy;

beforeEach(() => {
windowSpy = createWindow();
});

afterEach(() => {
windowSpy.mockReset();
});

describe('events', () => {
describe('off.ts', () => {
describe('off', () => {
it('should remove listener', () => {
const listener = jest.fn();
const emit = () => dispatchWindowEvent('viewport_changed', {
const emit = () => dispatchWindowMessageEvent('viewport_changed', {
height: 123,
width: 321,
is_expanded: false,
Expand Down
17 changes: 13 additions & 4 deletions packages/bridge/__tests__/events/on.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { on } from '../../src/index.js';
import { dispatchWindowEvent, mockWindow } from '../__utils__/window.js';
import { createWindow, type WindowSpy } from '../__utils__/createWindow.js';
import { dispatchWindowMessageEvent } from '../__utils__/dispatchWindowMessageEvent.js';

mockWindow();
let windowSpy: WindowSpy;

beforeEach(() => {
windowSpy = createWindow();
});

afterEach(() => {
windowSpy.mockReset();
});

describe('events', () => {
describe('on.ts', () => {
Expand All @@ -16,15 +25,15 @@ describe('events', () => {
is_expanded: false,
is_state_stable: false,
};
dispatchWindowEvent('viewport_changed', eventData);
dispatchWindowMessageEvent('viewport_changed', eventData);

expect(listener).toHaveBeenCalledTimes(1);
expect(listener).toHaveBeenCalledWith(eventData);
});

it('should remove listener in case, returned callback was called', () => {
const listener = jest.fn();
const emit = () => dispatchWindowEvent('viewport_changed', {
const emit = () => dispatchWindowMessageEvent('viewport_changed', {
height: 123,
width: 321,
is_expanded: false,
Expand Down
15 changes: 12 additions & 3 deletions packages/bridge/__tests__/events/onTelegramEvent.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { onTelegramEvent } from '../../src/events/onTelegramEvent.js';
import { dispatchWindowEvent, mockWindow } from '../__utils__/window.js';
import { createWindow, type WindowSpy } from '../__utils__/createWindow.js';
import { dispatchWindowMessageEvent } from '../__utils__/dispatchWindowMessageEvent.js';

mockWindow();
let windowSpy: WindowSpy;

beforeEach(() => {
windowSpy = createWindow();
});

afterEach(() => {
windowSpy.mockReset();
});

describe('events', () => {
describe('onTelegramEvent.ts', () => {
Expand All @@ -10,7 +19,7 @@ describe('events', () => {
const callback = jest.fn();
onTelegramEvent(callback);

dispatchWindowEvent('qr_text_received', {});
dispatchWindowMessageEvent('qr_text_received', {});

expect(callback).toHaveBeenCalledTimes(1);
expect(callback).toHaveBeenCalledWith('qr_text_received', {});
Expand Down
Loading

0 comments on commit 93e3eb2

Please sign in to comment.