From 548a0aa8618d226cd99eaa826a42305f14cd8dd6 Mon Sep 17 00:00:00 2001 From: koudaiii Date: Wed, 18 Sep 2024 21:42:27 +0900 Subject: [PATCH 1/5] [WIP] From cea11d34b8ffd765ba6d1f8a7acae75c3bc95a7c Mon Sep 17 00:00:00 2001 From: koudaiii Date: Thu, 19 Sep 2024 00:57:05 +0900 Subject: [PATCH 2/5] Add template --- src/content.js | 15 +++++++ tests/unit/content.test.js | 81 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/src/content.js b/src/content.js index b321c73..be37f88 100644 --- a/src/content.js +++ b/src/content.js @@ -6,6 +6,21 @@ const languageLabels = { // Add more language labels as needed. For example: 'fr-fr': 'Dernière mise à jour le', }; +// timeAgoLabels is a dictionary that maps message from language codes to the corresponding language +// Default timeAgoLabels is 'years ago', 'days ago', 'hours ago', 'minutes ago', 'just now' +// Add more timeAgoLabels as needed +const timeAgoLabels = { + 'ja-jp': { + years: '年前に更新', + days: '日前に更新', + hours: '時間前に更新', + minutes: '分前に更新', + justNow: '今更新されたばかり', + }, + // Add more language labels as needed. For example: + // 'fr-fr': { years: 'il y a ans', days: 'il y a jours', hours: 'il y a heures', minutes: 'il y a minutes', justNow: 'à l\'instant' }, +}; + (async () => { // Get current URL const currentUrl = window.location.href; diff --git a/tests/unit/content.test.js b/tests/unit/content.test.js index d768e09..6536788 100644 --- a/tests/unit/content.test.js +++ b/tests/unit/content.test.js @@ -8,4 +8,85 @@ describe('URL Check in Content Script', () => { const currentUrl = 'https://learn.microsoft.com/en-us/azure/virtual-machines/overview'; expect(currentUrl.startsWith('https://learn.microsoft.com/ja-jp/')).toBe(false); }); + test('should match "年前に更新"', () => { + const textContent = '2 年前に更新'; + const match = textContent.match(/(年|日|時間|分)前に更新|(今更新されたばかり)/); + expect(match).not.toBeNull(); + expect(match[0]).toBe('年前に更新'); + }); + + test('should match "日前に更新"', () => { + const textContent = '3 日前に更新'; + const match = textContent.match(/(年|日|時間|分)前に更新|(今更新されたばかり)/); + expect(match).not.toBeNull(); + expect(match[0]).toBe('日前に更新'); + }); + + test('should match "時間前に更新"', () => { + const textContent = '5 時間前に更新'; + const match = textContent.match(/(年|日|時間|分)前に更新|(今更新されたばかり)/); + expect(match).not.toBeNull(); + expect(match[0]).toBe('時間前に更新'); + }); + + test('should match "分前に更新"', () => { + const textContent = '10 分前に更新'; + const match = textContent.match(/(年|日|時間|分)前に更新|(今更新されたばかり)/); + expect(match).not.toBeNull(); + expect(match[0]).toBe('分前に更新'); + }); + + test('should match "今更新されたばかり"', () => { + const textContent = '今更新されたばかり'; + const match = textContent.match(/(年|日|時間|分)前に更新|(今更新されたばかり)/); + expect(match).not.toBeNull(); + expect(match[0]).toBe('今更新されたばかり'); + }); + + test('should not match unrelated text', () => { + const textContent = 'This is some unrelated text'; + const match = textContent.match(/(年|日|時間|分)前に更新|(今更新されたばかり)/); + expect(match).toBeNull(); + }); + + test('should match "years ago"', () => { + const textContent = '2 years ago'; + const match = textContent.match(/(years|days|hours|minutes) ago|just now/); + expect(match).not.toBeNull(); + expect(match[0]).toBe('years ago'); + }); + + test('should match "days ago"', () => { + const textContent = '3 days ago'; + const match = textContent.match(/(years|days|hours|minutes) ago|just now/); + expect(match).not.toBeNull(); + expect(match[0]).toBe('days ago'); + }); + + test('should match "hours ago"', () => { + const textContent = '5 hours ago'; + const match = textContent.match(/(years|days|hours|minutes) ago|just now/); + expect(match).not.toBeNull(); + expect(match[0]).toBe('hours ago'); + }); + + test('should match "minutes ago"', () => { + const textContent = '10 minutes ago'; + const match = textContent.match(/(years|days|hours|minutes) ago|just now/); + expect(match).not.toBeNull(); + expect(match[0]).toBe('minutes ago'); + }); + + test('should match "just now"', () => { + const textContent = 'just now'; + const match = textContent.match(/(years|days|hours|minutes) ago|just now/); + expect(match).not.toBeNull(); + expect(match[0]).toBe('just now'); + }); + + test('should not match unrelated text', () => { + const textContent = 'This is some unrelated text'; + const match = textContent.match(/(years|days|hours|minutes) ago|just now/); + expect(match).toBeNull(); + }); }); From 81919da98a7f1acae22329fd6da44ec1f5c577f1 Mon Sep 17 00:00:00 2001 From: koudaiii Date: Thu, 19 Sep 2024 00:57:37 +0900 Subject: [PATCH 3/5] cosmetic --- tests/e2e/content.e2e.test.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/e2e/content.e2e.test.js b/tests/e2e/content.e2e.test.js index 6e840e7..3c8032f 100644 --- a/tests/e2e/content.e2e.test.js +++ b/tests/e2e/content.e2e.test.js @@ -83,14 +83,15 @@ describe('learn.microsoft.com Update Checker E2E Test', () => { ]; for (const timezone of timezones) { + console.log("timezone:", timezone); testCases.forEach((testCase) => { + console.log("testCase:", testCase); test(`should display English update date on ${testCase.url} with ${testCase.themeColor} theme in ${testCase.prefersColorScheme} mode`, async () => { await page.goto(testCase.url); await page.emulateMediaFeatures([ { name: "prefers-color-scheme", value: testCase.prefersColorScheme }, ]); await page.emulateTimezone(timezone); - console.log("timezone:", timezone); // Click the button to set the theme to the desired color scheme await page.evaluate((themeColor) => { @@ -99,7 +100,6 @@ describe('learn.microsoft.com Update Checker E2E Test', () => { }, testCase.themeColor); await page.waitForSelector('button[aria-pressed="true"]'); - // Wait for the time element with the 'data-article-date' attribute to be added await page.waitForSelector('time[data-article-date]'); @@ -129,7 +129,6 @@ describe('learn.microsoft.com Update Checker E2E Test', () => { { name: "prefers-color-scheme", value: testCase.prefersColorScheme }, ]); await page.emulateTimezone(timezone); - console.log("timezone:", timezone); // Click the button to set the theme to the desired color scheme await page.evaluate((themeColor) => { @@ -150,7 +149,6 @@ describe('learn.microsoft.com Update Checker E2E Test', () => { test('should run script with jp-learn-microsoft-com-update-checker-debug flag', async () => { await page.goto('https://learn.microsoft.com/ja-jp/azure/virtual-machines/overview?jp-learn-microsoft-com-update-checker-debug=true'); await page.emulateTimezone(timezone); - console.log("timezone:", timezone); // Wait for the paragraph element with the 'alert' class to be added await page.waitForSelector('p.alert'); From 8020ee790a28f4bf0acbe5b78410177819100c7f Mon Sep 17 00:00:00 2001 From: koudaiii Date: Thu, 19 Sep 2024 00:59:37 +0900 Subject: [PATCH 4/5] implement display the update information --- src/content.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/content.js b/src/content.js index be37f88..22fd2af 100644 --- a/src/content.js +++ b/src/content.js @@ -61,6 +61,38 @@ const timeAgoLabels = { const englishDate = new Date(englishDateStr); // Add update info to current page + // Calculate the difference in time between the current date and the English update date + const currentDate = new Date(); + const timeDifference = currentDate - englishDate; + + // Create a new paragraph element to display the update information + let timeAgo; + const years = Math.floor(timeDifference / (1000 * 60 * 60 * 24 * 365)); + const days = Math.floor((timeDifference % (1000 * 60 * 60 * 24 * 365)) / (1000 * 60 * 60 * 24)); + const hours = Math.floor((timeDifference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + const minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60)); + + const labels = timeAgoLabels[currentLang] || { + years: 'years ago', + days: 'days ago', + hours: 'hours ago', + minutes: 'minutes ago', + justNow: 'just now' + }; + + if (years > 0) { + timeAgo = ` ${years} ${labels.years}`; + } else if (days > 0) { + timeAgo = ` ${days} ${labels.days}`; + } else if (hours > 0) { + timeAgo = ` ${hours} ${labels.hours}`; + } else if (minutes > 0) { + timeAgo = ` ${minutes} ${labels.minutes}`; + } else { + timeAgo = labels.justNow; + } + let timeAgoStr = ` (${timeAgo})`; + const updateInfo = document.createElement("p"); dataArticleDateElement.parentElement.appendChild(updateInfo); @@ -79,6 +111,8 @@ const timeAgoLabels = { console.log("English date:", englishDate); console.log("Article date:", articleDate); + console.log("timeAgoStr:", timeAgoStr); + // Compare English date and Article date if (englishDate > articleDate || debug === "true") { // Display alert if English page is updated From 584d43778252e38a41f0d1b11a23778c3846b5cd Mon Sep 17 00:00:00 2001 From: koudaiii Date: Thu, 19 Sep 2024 01:00:18 +0900 Subject: [PATCH 5/5] print display and add e2e test --- src/content.js | 2 +- tests/e2e/content.e2e.test.js | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/content.js b/src/content.js index 22fd2af..b75640d 100644 --- a/src/content.js +++ b/src/content.js @@ -131,7 +131,7 @@ const timeAgoLabels = { const languageLabel = languageLabels[currentLang] || 'last updated on'; // Display update info - updateInfo.innerHTML = informationIcon + `${languageLabel}: ${englishDate.toLocaleDateString(currentLang)}`; + updateInfo.innerHTML = informationIcon + `${languageLabel}: ${englishDate.toLocaleDateString(currentLang)}${timeAgoStr}`; } updateClass(); const observer = new MutationObserver(updateClass); diff --git a/tests/e2e/content.e2e.test.js b/tests/e2e/content.e2e.test.js index 3c8032f..02d28f1 100644 --- a/tests/e2e/content.e2e.test.js +++ b/tests/e2e/content.e2e.test.js @@ -120,6 +120,21 @@ describe('learn.microsoft.com Update Checker E2E Test', () => { return textElement !== null; }, testCase.textElementSelector); expect(hasTextColorClass).toBe(true); + + // get text content. e.g. '2023/12/21 英語版の更新日: 2023/12/21 (271日前に更新)' + const textContentStr = await page.evaluate(() => { + const visibilityHiddenVisualDiffElement = document.querySelector('li.visibility-hidden-visual-diff'); + return visibilityHiddenVisualDiffElement ? visibilityHiddenVisualDiffElement.innerText : null; + }); + console.log("textContentStr:", textContentStr); + + let defaultUpdatePattern = /(years|days|hours|minutes) ago|(just now)/; + if (testCase.url.includes('ja-jp')) { + defaultUpdatePattern = /(年|日|時間|分)前に更新|(今更新されたばかり)/; + } + let match = textContentStr.match(defaultUpdatePattern); + console.log("match:", match); + expect(!!match).toBe(true); }); test(`should not run script on en-us pages with ${testCase.themeColor} theme in ${testCase.prefersColorScheme} mode`, async () => {