Skip to content

Commit

Permalink
FEC-14246-add-cypress-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Roee Dean authored and Roee Dean committed Dec 24, 2024
1 parent 9580b11 commit 0352a0b
Show file tree
Hide file tree
Showing 16 changed files with 1,450 additions and 21 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/run_canary.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ on:
- master

jobs:
test:
uses: kaltura/playkit-js-common/.github/workflows/cypress.yml@master
secrets: inherit

canary:
if: ${{ github.actor != 'PlaykitJs-Bot' }}
uses: kaltura/playkit-js-common/.github/workflows/canary_plugin.yaml@master
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/run_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ on:
- "*"

jobs:
tests:
uses: kaltura/playkit-js-common/.github/workflows/cypress.yml@master
secrets: inherit
running-tests:
uses: kaltura/ovp-pipelines-pub/.github/workflows/player_tests.yaml@master
with:
Expand Down
12 changes: 12 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {defineConfig} from 'cypress';

export default defineConfig({
experimentalWebKitSupport: true,
chromeWebSecurity: false,
defaultCommandTimeout: 30000,
fileServerFolder: 'cypress/public',
e2e: {
supportFile: false,
watchForFileChanges: false
}
});
2 changes: 2 additions & 0 deletions cypress/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
public/playkit-related.js
public/playkit-related.js.map
284 changes: 284 additions & 0 deletions cypress/e2e/related.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
declare global {
interface Window {
KalturaPlayer: {
setup: (config: any) => any;
getPlayer: () => any;
};
}
}

import {
clickOnNextButton,
clickOnListToggle,
clickOnCloseButton,
clickOnRelatedEntry
} from './utils/actions';
import {
expectElementContains,
expectElementDoesntExist,
expectElementExists,
expectRelatedGridVisible,
expectRelatedListVisible,
setupAndExpect
} from './utils/expects';
import {
getRelatedGridElement,
getRelatedListElement,
getNextButtonElement,
getListToggleButtonElement,
getCountdownElement,
getCloseButtonElement
} from './utils/getters';
import {loadPlayerAndSetMedia, mockRelatedEntries, getPlayer} from './utils/setup';
import {DEFAULT_COUNTDOWN_TIME, DEFAULT_ENTRIES_LIMIT} from './utils/values';

describe('Related plugin', () => {
describe('entry relation methods', () => {
beforeEach(() => {
// Mock playlist API response
cy.intercept('GET', '**/service/playlist/execute*', {
body: {
data: mockRelatedEntries
}
});

// Mock context API response
cy.intercept('GET', '**/service/playlist*', req => {
if (req.body?.filter?.objectType === 'KalturaMediaEntryFilterForPlaylist') {
req.reply({
data: mockRelatedEntries
});
}
});
});

it('should load related entries from playlistId', () => {
const playlistId = 'test_playlist_123';
setupAndExpect({playlistId}, loadPlayerAndSetMedia, () => {
clickOnListToggle();
expectElementExists(getRelatedListElement);
expectElementContains(getRelatedListElement, [mockRelatedEntries[0].name, mockRelatedEntries[1].name]);
});
});

it('should load related entries from entryList', () => {
const entryList = mockRelatedEntries.map(entry => ({
entryId: entry.id,
...entry
}));
setupAndExpect({entryList}, loadPlayerAndSetMedia, () => {
clickOnListToggle();
expectElementExists(getRelatedListElement);
expectElementContains(getRelatedListElement, [mockRelatedEntries[0].name, mockRelatedEntries[1].name]);
});
});

it('should load related entries from sourcesList', () => {
const sourcesList = mockRelatedEntries.map(entry => ({
id: entry.id,
duration: entry.duration,
metadata: {
name: entry.name,
description: entry.description
},
poster: entry.thumbnailUrl,
progressive: [
{
mimetype: 'video/mp4',
url: 'test-video.mp4'
}
]
}));
setupAndExpect({sourcesList}, loadPlayerAndSetMedia, () => {
clickOnListToggle();
expectElementExists(getRelatedListElement);
expectElementContains(getRelatedListElement, [mockRelatedEntries[0].name, mockRelatedEntries[1].name]);
});
});

it('should load related entries using context when useContext is true', () => {
setupAndExpect({useContext: true, entriesByContextLimit: 2}, loadPlayerAndSetMedia, () => {
clickOnListToggle();
expectElementExists(getRelatedListElement);
expectElementContains(getRelatedListElement, [mockRelatedEntries[0].name, mockRelatedEntries[1].name]);
});
});

it('should prioritize playlistId over other methods', () => {
const playlistEntries = [
{
id: 'playlist_1',
name: 'Playlist Video 1',
description: 'From Playlist',
thumbnailUrl: 'thumb1.jpg',
duration: 120
}
];

// Mock playlist response with different entries
cy.intercept('GET', '**/service/playlist/execute*', {
body: {
data: playlistEntries
}
});

setupAndExpect({
playlistId: 'test_playlist',
entryList: mockRelatedEntries,
sourcesList: mockRelatedEntries,
useContext: true
}, loadPlayerAndSetMedia, () => {
clickOnListToggle();
expectElementExists(getRelatedListElement);
expectElementContains(getRelatedListElement, [playlistEntries[0].name]);
expectElementDoesntExist(() => cy.contains(mockRelatedEntries[0].name));
});
});

it('should prioritize entryList over sourcesList and context', () => {
const sourcesList = [{
id: 'source_1',
metadata: { name: 'Source Video' },
progressive: [{ mimetype: 'video/mp4', url: 'test.mp4' }]
}];

setupAndExpect({
entryList: mockRelatedEntries,
sourcesList,
useContext: true
}, loadPlayerAndSetMedia, () => {
clickOnListToggle();
expectElementExists(getRelatedListElement);
expectElementContains(getRelatedListElement, [mockRelatedEntries[0].name]);
expectElementDoesntExist(() => cy.contains('Source Video'));
});
});
});

describe('initialization', () => {
it('should not show related content by default when video starts', () => {
setupAndExpect({}, loadPlayerAndSetMedia, () => {
expectElementDoesntExist(getRelatedGridElement);
expectElementDoesntExist(getRelatedListElement);
});
});

it('should load with provided related entries', () => {
setupAndExpect({entryList: mockRelatedEntries}, loadPlayerAndSetMedia, () => {
clickOnListToggle();
expectElementExists(getRelatedListElement);
expectElementContains(getRelatedListElement, [mockRelatedEntries[0].name, mockRelatedEntries[1].name]);
});
});
});

describe('list view', () => {
beforeEach(() => {
cy.intercept('GET', '**/service/playlist*', {
body: {
data: mockRelatedEntries
}
});
});

it('should show list view when toggle button is clicked', () => {
setupAndExpect({entryList: mockRelatedEntries}, loadPlayerAndSetMedia, () => {
expectElementDoesntExist(getRelatedListElement);
clickOnListToggle();
expectElementExists(getRelatedListElement);
});
});

it('should hide list view when close button is clicked', () => {
setupAndExpect({entryList: mockRelatedEntries}, loadPlayerAndSetMedia, () => {
clickOnListToggle();
expectElementExists(getRelatedListElement);
clickOnCloseButton();
expectElementDoesntExist(getRelatedListElement);
});
});

it('should play selected entry when clicked', () => {
setupAndExpect({entryList: mockRelatedEntries}, loadPlayerAndSetMedia, () => {
clickOnListToggle();
clickOnRelatedEntry(0);
// Verify the video source has changed to the selected entry
cy.window().then(win => {
expect((win as any).KalturaPlayer.getPlayer().sources.id).to.equal(mockRelatedEntries[0].id);
});
});
});
});

describe('auto continue', () => {
it('should show countdown when video ends with autoContinue enabled', () => {
setupAndExpect({entryList: mockRelatedEntries, autoContinue: true}, loadPlayerAndSetMedia, player => {
player.currentTime = player.duration;
expectElementExists(getCountdownElement);
});
});

it('should not show countdown when autoContinue is disabled', () => {
setupAndExpect({entryList: mockRelatedEntries, autoContinue: false}, loadPlayerAndSetMedia, player => {
player.currentTime = player.duration;
expectElementDoesntExist(getCountdownElement);
});
});

it('should auto continue to next video after countdown', () => {
setupAndExpect(
{entryList: mockRelatedEntries, autoContinue: true, autoContinueTime: 1},
loadPlayerAndSetMedia,
player => {
player.currentTime = player.duration;
cy.wait(1500).then(() => {
cy.window().then(win => {
expect((win as any).KalturaPlayer.getPlayer().sources.id).to.equal(mockRelatedEntries[0].id);
});
});
}
);
});
});

describe('grid view', () => {
it('should show grid view on pause when showOnPlaybackPaused is true', () => {
setupAndExpect({entryList: mockRelatedEntries, showOnPlaybackPaused: true}, loadPlayerAndSetMedia, player => {
player.pause();
expectElementExists(getRelatedGridElement);
});
});

it('should not show grid view on pause when showOnPlaybackPaused is false', () => {
setupAndExpect({entryList: mockRelatedEntries, showOnPlaybackPaused: false}, loadPlayerAndSetMedia, player => {
player.pause();
expectElementDoesntExist(getRelatedGridElement);
});
});

it('should play selected entry from grid when clicked', () => {
setupAndExpect({entryList: mockRelatedEntries, showOnPlaybackPaused: true}, loadPlayerAndSetMedia, player => {
player.pause();
clickOnRelatedEntry(0);
expect(getPlayer().sources.id).to.equal(mockRelatedEntries[0].id);
});
});
});

describe('next button', () => {
it('should show next button when there are related entries', () => {
setupAndExpect({entryList: mockRelatedEntries}, loadPlayerAndSetMedia, () => {
expectElementExists(getNextButtonElement);
});
});

it('should play next entry when next button is clicked', () => {
setupAndExpect({entryList: mockRelatedEntries}, loadPlayerAndSetMedia, () => {
clickOnNextButton();
cy.window().then(win => {
expect((win as any).KalturaPlayer.getPlayer().sources.id).to.equal(mockRelatedEntries[0].id);
});
});
});
});
});
17 changes: 17 additions & 0 deletions cypress/e2e/utils/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {getNextButtonElement, getListToggleButtonElement, getCloseButtonElement, getRelatedEntryElement} from './getters';

export const clickOnNextButton = () => {
getNextButtonElement().click({force: true});
};

export const clickOnListToggle = () => {
getListToggleButtonElement().click({force: true});
};

export const clickOnCloseButton = () => {
getCloseButtonElement().click({force: true});
};

export const clickOnRelatedEntry = (index: number) => {
getRelatedEntryElement(index).click({force: true});
};
34 changes: 34 additions & 0 deletions cypress/e2e/utils/expects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {getRelatedGridElement, getRelatedListElement, getNextButtonElement} from './getters';
import {loadPlayerAndSetMedia} from './setup';

export const setupAndExpect = (pluginConfig: any, setupFunc: (pluginConfig: any) => Promise<any>, expectFunc: (setupResult: any) => void) => {
setupFunc(pluginConfig).then(result => {
expectFunc(result);
});
};

export const expectElementExists = (getElement: () => any) => {
getElement().should('exist');
};

export const expectElementDoesntExist = (getElement: () => any) => {
getElement().should('not.exist');
};

export const expectElementContains = (getElement: () => any, texts: string[]) => {
for (const text of texts) {
getElement().contains(text).should('exist');
}
};

export const expectRelatedGridVisible = (pluginConfig: any) => {
setupAndExpect(pluginConfig, loadPlayerAndSetMedia, () => {
expectElementExists(getRelatedGridElement);
});
};

export const expectRelatedListVisible = (pluginConfig: any) => {
setupAndExpect(pluginConfig, loadPlayerAndSetMedia, () => {
expectElementExists(getRelatedListElement);
});
};
7 changes: 7 additions & 0 deletions cypress/e2e/utils/getters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const getRelatedGridElement = () => cy.get('[data-testid="related-grid"]');
export const getRelatedListElement = () => cy.get('[data-testid="related-list"]');
export const getRelatedEntryElement = (index: number) => cy.get(`[data-testid="related-entry-${index}"]`);
export const getNextButtonElement = () => cy.get('[data-testid="related-next-button"]');
export const getListToggleButtonElement = () => cy.get('.listToggleButton');
export const getCountdownElement = () => cy.get('[data-testid="related-countdown"]');
export const getCloseButtonElement = () => cy.get('[data-testid="related-close-button"]');
Loading

0 comments on commit 0352a0b

Please sign in to comment.