Skip to content

Commit

Permalink
Merge pull request #2042 from exadel-inc/test/esl-share-tests
Browse files Browse the repository at this point in the history
[ESL Share]: Tests
  • Loading branch information
ala-n authored Nov 22, 2023
2 parents 5d5968b + 236d960 commit 7832bd7
Show file tree
Hide file tree
Showing 11 changed files with 515 additions and 8 deletions.
7 changes: 0 additions & 7 deletions src/modules/esl-share/core/esl-share-action-registry.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {memoize} from '../../esl-utils/decorators';

import type {ESLShareActionType, ESLShareBaseAction} from './esl-share-action';
import type {ESLShareButton} from './esl-share-button';

/**
* ESLShareActionRegistry class to store share actions
Expand Down Expand Up @@ -34,10 +33,4 @@ export class ESLShareActionRegistry {
if (!name) return null;
return this.actionsMap.get(name.toLowerCase()) || null;
}

/** Does the share action on passed Share button {@link ESLShareButton} */
public share(button: ESLShareButton): void {
const action = this.get(button.shareAction);
action && action.share(button);
}
}
2 changes: 1 addition & 1 deletion src/modules/esl-share/core/esl-share-button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class ESLShareButton extends ESLBaseElement {
const $button = document.createElement(this.is) as InstanceType<T>;
if (buttonName) {
$button.name = buttonName;
$button.initIcon();
$button.defaultIcon = true;
}
return $button;
}
Expand Down
57 changes: 57 additions & 0 deletions src/modules/esl-share/test/actions/copy-action.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import '../../actions/copy-action';
import {ESLShareActionRegistry} from '../../core/esl-share-action-registry';
import {ESLShareButton} from '../../core/esl-share-button';

describe('ESLShare: "copy" action import', () => {
test('"copy" action was registered when importing', () => {
expect(ESLShareActionRegistry.instance.has('copy')).toBe(true);
});
});

describe('ESLShare: "copy" action public API', () => {
const originalClipboard = {...navigator.clipboard};
const mockClipboard = {
writeText: jest.fn(),
};
const copyAction = ESLShareActionRegistry.instance.get('copy');
const $button = ESLShareButton.create();

beforeAll(() => {
(navigator as any).clipboard = mockClipboard;

ESLShareButton.register();
document.body.appendChild($button);
$button.setAttribute('share-title', 'Test button title');
$button.setAttribute('share-url', '/test/button/url');
$button.setAttribute('additional', '{"alertText": "Copied to clipboard"}');
});

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

afterAll(() => {
document.body.innerHTML = '';
(navigator as any).clipboard = originalClipboard;
});

test('isAvailable should be true', () => {
expect(copyAction?.isAvailable).toBe(true);
});

test('should call navigation.clipboard.writeText() when share() calls', () => {
copyAction?.share($button);
expect(mockClipboard.writeText).toBeCalledWith('http://localhost/test/button/url');
});

test('should dispatch esl:alert:show with shareAdditional.alertText when share() calls', (done) => {
document.body.addEventListener('esl:alert:show', (e) => {
expect((e as CustomEvent).detail).toEqual({
cls: 'esl-share-alert',
html: '<span>Copied to clipboard</span>',
});
done();
}, {once: true});
copyAction?.share($button);
}, 10);
});
55 changes: 55 additions & 0 deletions src/modules/esl-share/test/actions/external-action.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import '../../actions/external-action';
import {ESLShareActionRegistry} from '../../core/esl-share-action-registry';
import {ESLShareButton} from '../../core/esl-share-button';

describe('ESLShare: "external" action import', () => {
test('"external" action was registered when importing', () => {
expect(ESLShareActionRegistry.instance.has('external')).toBe(true);
});
});

describe('ESLShare: "external" action public API', () => {
const originalCreateElement = document.createElement;
const mockAnchorElement = {click: jest.fn()};
Object.defineProperty(mockAnchorElement, 'href', {
get: () => (this as any)._href,
set: (value) => (this as any)._href = value,
});
const mockCreateElement = (tag: string) => {
if (tag === 'a') return mockAnchorElement as any;
return originalCreateElement(tag);
};

const externalAction = ESLShareActionRegistry.instance.get('external');
const $button = ESLShareButton.create();

beforeAll(() => {
ESLShareButton.register();
document.body.appendChild($button);
$button.setAttribute('link', '//host/sharer?title={title}&url={url}&t={t}&u={u}');
$button.setAttribute('share-title', 'Test btn title');
$button.setAttribute('share-url', '/test/url');
});

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

afterAll(() => {
document.body.innerHTML = '';
jest.restoreAllMocks();
});

test('should be available', () => {
expect(externalAction?.isAvailable).toBe(true);
});

test('should simulate click() on anchor to make external jump (also checks link placeholders replacement)', () => {
jest.spyOn(document, 'createElement').mockImplementation(mockCreateElement);
externalAction?.share($button);
expect(mockAnchorElement.click).toBeCalledTimes(1);
expect((mockAnchorElement as any).href).toBe(
'//host/sharer?title=Test%20btn%20title&url=http%3A%2F%2Flocalhost%2Ftest%2Furl&t=Test%20btn%20title&u=http%3A%2F%2Flocalhost%2Ftest%2Furl'
);
});
});
45 changes: 45 additions & 0 deletions src/modules/esl-share/test/actions/media-action.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import '../../actions/media-action';
import {ESLShareActionRegistry} from '../../core/esl-share-action-registry';
import {ESLShareButton} from '../../core/esl-share-button';

describe('ESLShare: "media" action import', () => {
test('"media" action was registered when importing', () => {
expect(ESLShareActionRegistry.instance.has('media')).toBe(true);
});
});

describe('ESLShare: "media" action public API', () => {
const mediaAction = ESLShareActionRegistry.instance.get('media');
const $button = ESLShareButton.create();

beforeAll(() => {
ESLShareButton.register();
document.body.appendChild($button);
$button.setAttribute('link', '//host/sharer?title={title}&url={url}&t={t}&u={u}');
$button.setAttribute('share-title', 'Test btn title');
$button.setAttribute('share-url', '/test/url');
});

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

afterAll(() => {
document.body.innerHTML = '';
jest.restoreAllMocks();
});

test('should be available', () => {
expect(mediaAction?.isAvailable).toBe(true);
});

test('should call window.open() with buttons link when share() (also checks link placeholders replacement)', () => {
const mockOpen = jest.spyOn(window, 'open').mockImplementation(() => null);
mediaAction?.share($button);
expect(mockOpen).toBeCalledWith(
'//host/sharer?title=Test%20btn%20title&url=http%3A%2F%2Flocalhost%2Ftest%2Furl&t=Test%20btn%20title&u=http%3A%2F%2Flocalhost%2Ftest%2Furl',
'_blank',
'scrollbars=0,resizable=1,menubar=0,left=100,top=100,width=750,height=500,toolbar=0,status=0'
);
});
});
46 changes: 46 additions & 0 deletions src/modules/esl-share/test/actions/native-action.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import '../../actions/native-action';
import {ESLShareActionRegistry} from '../../core/esl-share-action-registry';
import {ESLShareButton} from '../../core/esl-share-button';

describe('ESLShare: "native" action import', () => {
test('"native" action was registered when importing', () => {
expect(ESLShareActionRegistry.instance.has('native')).toBe(true);
});
});

describe('ESLShare: "native" action public API', () => {
const originalShare = navigator.share;
const mockShare = jest.fn();
const nativeAction = ESLShareActionRegistry.instance.get('native');
const $button = ESLShareButton.create();

beforeAll(() => {
(navigator as any).share = mockShare;

ESLShareButton.register();
document.body.appendChild($button);
$button.setAttribute('share-title', 'Test button title');
$button.setAttribute('share-url', '/test/button/url');
});

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

afterAll(() => {
document.body.innerHTML = '';
(navigator as any).share = originalShare;
});

test('should be available', () => {
expect(nativeAction?.isAvailable).toBe(true);
});

test('should call navigator.share() when share() calls', () => {
nativeAction?.share($button);
expect(mockShare).toBeCalledWith({
title: 'Test button title',
url: 'http://localhost/test/button/url',
});
});
});
36 changes: 36 additions & 0 deletions src/modules/esl-share/test/actions/print-action.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import '../../actions/print-action';
import {ESLShareActionRegistry} from '../../core/esl-share-action-registry';
import {ESLShareButton} from '../../core/esl-share-button';

describe('ESLShare: "print" action import', () => {
test('"print" action was registered when importing', () => {
expect(ESLShareActionRegistry.instance.has('print')).toBe(true);
});
});

describe('ESLShare: "print" action public API', () => {
const printAction = ESLShareActionRegistry.instance.get('print');
const $button = ESLShareButton.create();

beforeAll(() => {
ESLShareButton.register();
document.body.appendChild($button);
$button.setAttribute('share-title', 'Test button title');
$button.setAttribute('share-url', '/test/button/url');
});

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

afterAll(() => {
document.body.innerHTML = '';
jest.restoreAllMocks();
});

test('should call window.print() when share() calls', () => {
const mockPrint = jest.spyOn(window, 'print').mockImplementation(() => null);
printAction?.share($button);
expect(mockPrint).toBeCalled();
});
});
57 changes: 57 additions & 0 deletions src/modules/esl-share/test/esl-share-action-registry.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {ESLShareActionRegistry} from '../core/esl-share-action-registry';
import {ESLSharePrintAction} from '../actions/print-action';

describe('ESLShareActionRegistry tests', () => {
describe('ESLShareActionRegistry static API', () => {
test('ESLShareActionRegistry instance is a singleton', () => {
expect(ESLShareActionRegistry.instance).toBeInstanceOf(ESLShareActionRegistry);
expect(ESLShareActionRegistry.instance).toBe(ESLShareActionRegistry.instance);
});
});

describe('ESLShareActionRegistry public API', () => {

afterEach(() => {
ESLShareActionRegistry.instance['actionsMap'].clear();
});

test('should throw an error when register invalid action', () => {
const {instance} = ESLShareActionRegistry;
expect(() => instance.register({} as any)).toThrowError();
});

test('should registers action', () => {
const {instance} = ESLShareActionRegistry;
instance.register(ESLSharePrintAction);
expect(instance['actionsMap'].has('print')).toBe(true);
});

test('should register the same action just once', () => {
const {instance} = ESLShareActionRegistry;
instance.register(ESLSharePrintAction);
instance.register(ESLSharePrintAction);
instance.register(ESLSharePrintAction);
expect(instance['actionsMap'].size).toBe(1);
});

test('should check action availability', () => {
const {instance} = ESLShareActionRegistry;
instance.register(ESLSharePrintAction);
expect(instance.has('copy')).toBe(false);
expect(instance.has('print')).toBe(true);
});

test('should get action by name', () => {
const {instance} = ESLShareActionRegistry;
instance.register(ESLSharePrintAction);
const action = instance.get('print');
expect(action).toBeInstanceOf(ESLSharePrintAction);
});

test('should return null when trying to get an unregistered action', () => {
const {instance} = ESLShareActionRegistry;
const action = instance.get('print');
expect(action).toBe(null);
});
});
});
Loading

0 comments on commit 7832bd7

Please sign in to comment.