Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ESL Share]: Tests #2042

Merged
merged 8 commits into from
Nov 22, 2023
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 @@ -24,7 +24,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