mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 07:43:35 +00:00
* remove placeholder image * add videos for setup extension * add support for mobile viewports * add mobile/responsiveness for setup extension page * add videos from `assets.bitwarden.com` * align with figma for borders and shadow * make text responsive for setup headings * remove period * add tests * add tests for video sequence * force font weight on `h2` * add 8px to bottom margin of video container
171 lines
5.3 KiB
TypeScript
171 lines
5.3 KiB
TypeScript
import { ComponentFixture, fakeAsync, TestBed, tick } from "@angular/core/testing";
|
|
import { By } from "@angular/platform-browser";
|
|
import { provideNoopAnimations } from "@angular/platform-browser/animations";
|
|
import { RouterModule } from "@angular/router";
|
|
|
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
|
|
import { AddExtensionVideosComponent } from "./add-extension-videos.component";
|
|
|
|
describe("AddExtensionVideosComponent", () => {
|
|
let fixture: ComponentFixture<AddExtensionVideosComponent>;
|
|
let component: AddExtensionVideosComponent;
|
|
|
|
// Mock HTMLMediaElement load to stop the video file from being loaded
|
|
Object.defineProperty(HTMLMediaElement.prototype, "load", {
|
|
value: jest.fn(),
|
|
writable: true,
|
|
});
|
|
|
|
const play = jest.fn(() => Promise.resolve());
|
|
HTMLMediaElement.prototype.play = play;
|
|
|
|
beforeEach(async () => {
|
|
window.matchMedia = jest.fn().mockReturnValue(false);
|
|
play.mockClear();
|
|
|
|
await TestBed.configureTestingModule({
|
|
imports: [AddExtensionVideosComponent, RouterModule.forRoot([])],
|
|
providers: [
|
|
provideNoopAnimations(),
|
|
{ provide: I18nService, useValue: { t: (key: string) => key } },
|
|
],
|
|
}).compileComponents();
|
|
|
|
fixture = TestBed.createComponent(AddExtensionVideosComponent);
|
|
component = fixture.componentInstance;
|
|
fixture.detectChanges();
|
|
});
|
|
|
|
describe("loading pulse", () => {
|
|
it("shows loading spinner when all videos are not loaded", () => {
|
|
const loadingSpinners = fixture.debugElement.queryAll(By.css("[data-testid='video-pulse']"));
|
|
expect(loadingSpinners.length).toBe(3);
|
|
});
|
|
|
|
it("shows all pulses until all videos are loaded", () => {
|
|
let loadingSpinners = fixture.debugElement.queryAll(By.css("[data-testid='video-pulse']"));
|
|
expect(loadingSpinners.length).toBe(3);
|
|
|
|
// Simulate two video loaded
|
|
component["videoElements"].get(0)?.nativeElement.dispatchEvent(new Event("loadeddata"));
|
|
component["videoElements"].get(1)?.nativeElement.dispatchEvent(new Event("loadeddata"));
|
|
|
|
loadingSpinners = fixture.debugElement.queryAll(By.css("[data-testid='video-pulse']"));
|
|
|
|
expect(component["numberOfLoadedVideos"]).toBe(2);
|
|
expect(loadingSpinners.length).toBe(3);
|
|
});
|
|
});
|
|
|
|
describe("window resizing", () => {
|
|
beforeEach(() => {
|
|
component["numberOfLoadedVideos"] = 3;
|
|
fixture.detectChanges();
|
|
});
|
|
|
|
it("shows all videos when window is resized to desktop viewport", fakeAsync(() => {
|
|
component["variant"] = "mobile";
|
|
Object.defineProperty(component["document"].documentElement, "clientWidth", {
|
|
configurable: true,
|
|
value: 1000,
|
|
});
|
|
|
|
window.dispatchEvent(new Event("resize"));
|
|
|
|
fixture.detectChanges();
|
|
tick(50);
|
|
|
|
expect(
|
|
Array.from(component["videoElements"]).every(
|
|
(video) => video.nativeElement.parentElement?.style.opacity === "1",
|
|
),
|
|
).toBe(true);
|
|
}));
|
|
|
|
it("shows only the playing video when window is resized to mobile viewport", fakeAsync(() => {
|
|
component["variant"] = "desktop";
|
|
// readonly property needs redefining
|
|
Object.defineProperty(component["document"].documentElement, "clientWidth", {
|
|
value: 500,
|
|
});
|
|
|
|
const video1 = component["videoElements"].get(1);
|
|
Object.defineProperty(video1!.nativeElement, "paused", {
|
|
value: false,
|
|
});
|
|
|
|
window.dispatchEvent(new Event("resize"));
|
|
|
|
fixture.detectChanges();
|
|
tick(50);
|
|
|
|
expect(component["videoElements"].get(0)?.nativeElement.parentElement?.style.opacity).toBe(
|
|
"0",
|
|
);
|
|
expect(component["videoElements"].get(1)?.nativeElement.parentElement?.style.opacity).toBe(
|
|
"1",
|
|
);
|
|
expect(component["videoElements"].get(2)?.nativeElement.parentElement?.style.opacity).toBe(
|
|
"0",
|
|
);
|
|
}));
|
|
});
|
|
|
|
describe("video sequence", () => {
|
|
let firstVideo: HTMLVideoElement;
|
|
let secondVideo: HTMLVideoElement;
|
|
let thirdVideo: HTMLVideoElement;
|
|
|
|
beforeEach(() => {
|
|
component["numberOfLoadedVideos"] = 2;
|
|
component["onVideoLoad"]();
|
|
|
|
firstVideo = component["videoElements"].get(0)!.nativeElement;
|
|
secondVideo = component["videoElements"].get(1)!.nativeElement;
|
|
thirdVideo = component["videoElements"].get(2)!.nativeElement;
|
|
});
|
|
|
|
it("starts the video sequence when all videos are loaded", fakeAsync(() => {
|
|
tick();
|
|
|
|
expect(firstVideo.play).toHaveBeenCalled();
|
|
}));
|
|
|
|
it("plays videos in sequence", fakeAsync(() => {
|
|
tick(); // let first video play
|
|
|
|
play.mockClear();
|
|
firstVideo.onended!(new Event("ended")); // trigger next video
|
|
|
|
tick();
|
|
|
|
expect(secondVideo.play).toHaveBeenCalledTimes(1);
|
|
|
|
play.mockClear();
|
|
secondVideo.onended!(new Event("ended")); // trigger next video
|
|
|
|
tick();
|
|
|
|
expect(thirdVideo.play).toHaveBeenCalledTimes(1);
|
|
}));
|
|
|
|
it("doesn't play videos again when the user prefers no motion", fakeAsync(() => {
|
|
component["prefersReducedMotion"] = true;
|
|
|
|
tick();
|
|
firstVideo.onended!(new Event("ended"));
|
|
tick();
|
|
secondVideo.onended!(new Event("ended"));
|
|
tick();
|
|
|
|
play.mockClear();
|
|
|
|
thirdVideo.onended!(new Event("ended")); // trigger first video again
|
|
|
|
tick();
|
|
expect(play).toHaveBeenCalledTimes(0);
|
|
}));
|
|
});
|
|
});
|