aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/selenium.test.ts
blob: eb31a2ff6590fe458c3cfc7500e60a518fa9712b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
import { Builder, By, until, WebDriver, WebElement } from "selenium-webdriver";
import * as Chrome from "selenium-webdriver/chrome";
import * as Path from "path";

import * as fs from "fs";

test("Selenium Chrome test", async () => {
    let driver: WebDriver;
    try {
        driver = await setup();   
    } catch (e) {
        console.warn("A browser is probably not installed, skipping selenium tests");
        console.warn(e);

        return;
    }

    try {
        await waitForInstall(driver);
        // This video has no ads
        await goToVideo(driver, "jNQXAC9IVRw");

        await createSegment(driver, "4", "10.33", "0:04.000 to 0:10.330");

        await editSegments(driver, 0, "0:04.000", "0:10.330", "5", "13.211", "0:05.000 to 0:13.211", false);
        await autoskipSegment(driver, 5, 13.211);

        await setSegmentCategory(driver, 0, 1, false);
        await setSegmentActionType(driver, 0, 1, false);
        await editSegments(driver, 0, "0:05.000", "0:13.211", "5", "7.5", "0:05.000 to 0:07.500", false);
        await muteSkipSegment(driver, 5, 7.5);

        // Full video
        await setSegmentActionType(driver, 0, 2, false);
        await driver.wait(until.elementIsNotVisible(await getDisplayTimeBox(driver, 0)));

        await toggleWhitelist(driver);
        await toggleWhitelist(driver);

    } catch (e) {
        // Save file incase there is a layout change
        const source = await driver.getPageSource();

        if (!fs.existsSync("./test-results")) fs.mkdirSync("./test-results"); 
        fs.writeFileSync("./test-results/source.html", source);
        
        throw e;
    } finally {
        await driver.quit();
    }
}, 100_000);

async function setup(): Promise<WebDriver> {
    const options = new Chrome.Options();
    options.addArguments("--load-extension=" + Path.join(__dirname, "../dist/"));
    options.addArguments("--mute-audio");
    options.addArguments("--disable-features=PreloadMediaEngagementData, MediaEngagementBypassAutoplayPolicies");
    options.addArguments("--headless=new");
    options.addArguments("--window-size=1920,1080");

    const driver = await new Builder().forBrowser("chrome").setChromeOptions(options).build();
    driver.manage().setTimeouts({
        implicit: 5000
    });

    return driver;
}

async function waitForInstall(driver: WebDriver, startingTab = 0): Promise<void> {
    // Selenium only knows about the one tab it's on,
    // so we can't wait for the help page to appear
    await driver.sleep(3000);

    const handles = await driver.getAllWindowHandles();
    await driver.switchTo().window(handles[startingTab]);
}

async function goToVideo(driver: WebDriver, videoId: string): Promise<void> {
    await driver.get("https://www.youtube.com/watch?v=" + videoId);
    await driver.wait(until.elementIsVisible(await driver.findElement(By.css(".ytd-video-primary-info-renderer, #above-the-fold"))));
}

async function createSegment(driver: WebDriver, startTime: string, endTime: string, expectedDisplayedTime: string): Promise<void> {
    const startSegmentButton = await driver.findElement(By.id("startSegmentButton"));
    const cancelSegmentButton = await driver.findElement(By.id("cancelSegmentButton"));
    await driver.executeScript("document.querySelector('video').currentTime = " + startTime);

    await startSegmentButton.click();
    await driver.wait(until.elementIsVisible(cancelSegmentButton));

    await driver.executeScript("document.querySelector('video').currentTime = " + endTime);

    await startSegmentButton.click();
    await driver.wait(until.elementIsNotVisible(cancelSegmentButton));

    const submitButton = await driver.findElement(By.id("submitButton"));
    await submitButton.click();

    const sponsorTimeDisplays = await driver.findElements(By.className("sponsorTimeDisplay"));
    const sponsorTimeDisplay = sponsorTimeDisplays[sponsorTimeDisplays.length - 1];
    await driver.wait(until.elementTextIs(sponsorTimeDisplay, expectedDisplayedTime));
}

async function editSegments(driver: WebDriver, index: number, expectedStartTimeBox: string, expectedEndTimeBox: string,
    startTime: string, endTime: string, expectedDisplayedTime: string, openSubmitBox: boolean): Promise<void> {
    
    if (openSubmitBox) {
        const submitButton = await driver.findElement(By.id("submitButton"));
        await submitButton.click();
    }

    let editButton = await driver.findElement(By.id("sponsorTimeEditButtonSubmissionNotice" + index));
    const sponsorTimeDisplay = await getDisplayTimeBox(driver, index);
    await sponsorTimeDisplay.click();
    // Ensure edit time appears
    await driver.findElement(By.id("submittingTime0SubmissionNotice" + index));

    // Try the edit button too
    await editButton.click();
    await editButton.click();

    const startTimeBox = await getStartTimeBox(driver, index, expectedStartTimeBox);
    await startTimeBox.clear();
    await startTimeBox.sendKeys(startTime);

    const endTimeBox = await getEndTimeBox(driver, index, expectedEndTimeBox);
    await endTimeBox.clear();
    await endTimeBox.sendKeys(endTime);

    editButton = await driver.findElement(By.id("sponsorTimeEditButtonSubmissionNotice" + index));
    await editButton.click();

    await getDisplayTimeBox(driver, index, expectedDisplayedTime);
}

async function getStartTimeBox(driver: WebDriver, index: number, expectedStartTimeBox: string): Promise<WebElement> {
    const startTimeBox = await driver.findElement(By.id("submittingTime0SubmissionNotice" + index));
    expect((await startTimeBox.getAttribute("value"))).toBe(expectedStartTimeBox);
    return startTimeBox;
}

async function getEndTimeBox(driver: WebDriver, index: number, expectedEndTimeBox: string): Promise<WebElement> {
    const endTimeBox = await driver.findElement(By.id("submittingTime1SubmissionNotice" + index));
    expect((await endTimeBox.getAttribute("value"))).toBe(expectedEndTimeBox);
    return endTimeBox;
}

async function getDisplayTimeBox(driver: WebDriver, index: number, expectedDisplayedTime?: string): Promise<WebElement> {
    const sponsorTimeDisplay = (await driver.findElements(By.className("sponsorTimeDisplay")))[index];
    if (expectedDisplayedTime) {
        driver.wait(until.elementTextIs(sponsorTimeDisplay, expectedDisplayedTime));
    }

    return sponsorTimeDisplay;
}

async function setSegmentCategory(driver: WebDriver, index: number, categoryIndex: number, openSubmitBox: boolean): Promise<void> {
    if (openSubmitBox) {
        const submitButton = await driver.findElement(By.id("submitButton"));
        await submitButton.click();
    }

    const categorySelection = await driver.findElement(By.css(`#sponsorTimeCategoriesSubmissionNotice${index} > option:nth-child(${categoryIndex + 1})`));
    await categorySelection.click();
}

async function setSegmentActionType(driver: WebDriver, index: number, actionTypeIndex: number, openSubmitBox: boolean): Promise<void> {
    if (openSubmitBox) {
        const submitButton = await driver.findElement(By.id("submitButton"));
        await submitButton.click();
    }

    const actionTypeSelection = await driver.findElement(By.css(`#sponsorTimeActionTypesSubmissionNotice${index} > option:nth-child(${actionTypeIndex + 1})`));
    await actionTypeSelection.click();
}

async function autoskipSegment(driver: WebDriver, startTime: number, endTime: number): Promise<void> {
    const video = await driver.findElement(By.css("video"));

    await driver.executeScript("document.querySelector('video').currentTime = " + (startTime - 0.5));
    await driver.executeScript("document.querySelector('video').play()");

    await driver.sleep(1300);
    expect(parseFloat(await video.getAttribute("currentTime"))).toBeGreaterThan(endTime);
    await driver.executeScript("document.querySelector('video').pause()");
}

async function muteSkipSegment(driver: WebDriver, startTime: number, endTime: number): Promise<void> {
    const duration = endTime - startTime;
    const video = await driver.findElement(By.css("video"));

    await driver.executeScript("document.querySelector('video').currentTime = " + (startTime - 0.5));
    await driver.executeScript("document.querySelector('video').play()");

    await driver.sleep(1300);
    expect(await video.getAttribute("muted")).toEqual("true");

    await driver.sleep(duration * 1000 + 300);
    expect(await video.getAttribute("muted")).toBeNull(); // Default is null for some reason
    await driver.executeScript("document.querySelector('video').pause()");
}

async function toggleWhitelist(driver: WebDriver): Promise<void> {
    const popupButton = await driver.findElement(By.id("infoButton"));
    const rightControls = await driver.findElement(By.css(".ytp-right-controls"));
    await driver.actions().move({ origin: rightControls }).perform();
    if ((await popupButton.getCssValue("display")) !== "none") {
        await driver.actions().move({ origin: popupButton }).perform();
        await popupButton.click();
    }

    const popupFrame = await driver.findElement(By.css("#sponsorBlockPopupContainer iframe"));
    await driver.switchTo().frame(popupFrame);

    const whitelistButton = await driver.findElement(By.id("whitelistButton"));
    await driver.wait(until.elementIsVisible(whitelistButton));

    const whitelistText = await driver.findElement(By.id("whitelistChannel"));
    const whitelistDisplayed = await whitelistText.isDisplayed();

    await whitelistButton.click();
    if (whitelistDisplayed) {
        const unwhitelistText = await driver.findElement(By.id("unwhitelistChannel"));
        await driver.wait(until.elementIsVisible(unwhitelistText));
    } else {
        await driver.wait(until.elementIsVisible(whitelistText));
    }

    await driver.switchTo().defaultContent();
}