Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ __coverage__
csak-timelog.json
.idea/
debug/
test-results/

# Lefthook
lefthook-local.yml
Expand Down
3 changes: 2 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"syler.sass-indented",
"redhat.vscode-yaml",
"vue.volar",
"eamodio.gitlens"
"eamodio.gitlens",
"ms-playwright.playwright"
]
}
4 changes: 3 additions & 1 deletion _scripts/clean.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { join } from 'path'

const BUILD_PATH = join(import.meta.dirname, '..', 'build')
const DIST_PATH = join(import.meta.dirname, '..', 'dist')
const TEST_RESULTS_PATH = join(import.meta.dirname, '..', 'test-results')

await Promise.all([
rm(BUILD_PATH, { recursive: true, force: true }),
rm(DIST_PATH, { recursive: true, force: true })
rm(DIST_PATH, { recursive: true, force: true }),
rm(TEST_RESULTS_PATH, { recursive: true, force: true }),
])
135 changes: 69 additions & 66 deletions _scripts/webpack.main.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,74 +5,77 @@ const JsonMinimizerPlugin = require('json-minimizer-webpack-plugin')

const isDevMode = process.env.NODE_ENV === 'development'

/** @type {import('webpack').Configuration} */
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend hiding whitespaces when looking at the changes to this file.
Config was just wrapped in a method that is exported so the IS_TESTS env variable could be set properly: https://webpack.js.org/guides/environment-variables/ (I followed what was in this guide)

const config = {
name: 'main',
mode: process.env.NODE_ENV,
devtool: isDevMode ? 'eval-cheap-module-source-map' : false,
entry: {
main: path.join(__dirname, '../src/main/index.js'),
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/,
},
{
resource: path.resolve(__dirname, '../node_modules/mime-db/db.json'),
use: path.join(__dirname, 'mime-db-shrinking-loader.js')
}
],
generator: {
json: {
JSONParse: false
module.exports = (env) => {
/** @type {import('webpack').Configuration} */
const config = {
name: 'main',
mode: process.env.NODE_ENV,
devtool: isDevMode ? 'eval-cheap-module-source-map' : false,
entry: {
main: path.join(__dirname, '../src/main/index.js'),
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/,
},
{
resource: path.resolve(__dirname, '../node_modules/mime-db/db.json'),
use: path.join(__dirname, 'mime-db-shrinking-loader.js')
}
],
generator: {
json: {
JSONParse: false
}
}
}
},
// webpack defaults to only optimising the production builds, so having this here is fine
optimization: {
minimizer: [
'...', // extend webpack's list instead of overwriting it
new JsonMinimizerPlugin({
exclude: /\/locales\/.*\.json/
},
// webpack defaults to only optimising the production builds, so having this here is fine
optimization: {
minimizer: [
'...', // extend webpack's list instead of overwriting it
new JsonMinimizerPlugin({
exclude: /\/locales\/.*\.json/
})
]
},
node: {
__dirname: isDevMode,
__filename: isDevMode
},
plugins: [
new webpack.DefinePlugin({
'process.platform': `'${process.platform}'`,
'process.env.IS_ELECTRON_MAIN': true,
'process.env.IS_TESTS': env.IS_TESTS
})
]
},
node: {
__dirname: isDevMode,
__filename: isDevMode
},
plugins: [
new webpack.DefinePlugin({
'process.platform': `'${process.platform}'`,
'process.env.IS_ELECTRON_MAIN': true
})
],
output: {
filename: '[name].js',
libraryTarget: 'commonjs2',
path: path.join(__dirname, '../dist'),
},
target: 'electron-main',
}
],
output: {
filename: '[name].js',
libraryTarget: 'commonjs2',
path: path.join(__dirname, '../dist'),
},
target: 'electron-main',
}

if (!isDevMode) {
config.plugins.push(
new CopyWebpackPlugin({
patterns: [
{
from: path.join(__dirname, '../static'),
to: path.join(__dirname, '../dist/static'),
globOptions: {
dot: true,
ignore: ['**/.*', '**/locales/**', '**/pwabuilder-sw.js', '**/manifest.json', '**/dashFiles/**', '**/storyboards/**'],
if (!isDevMode) {
config.plugins.push(
new CopyWebpackPlugin({
patterns: [
{
from: path.join(__dirname, '../static'),
to: path.join(__dirname, '../dist/static'),
globOptions: {
dot: true,
ignore: ['**/.*', '**/locales/**', '**/pwabuilder-sw.js', '**/manifest.json', '**/dashFiles/**', '**/storyboards/**'],
},
},
},
]
})
)
}
]
})
)
}

module.exports = config
return config
}
27 changes: 24 additions & 3 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { defineConfig } from "eslint/config";
import eslintPluginVue from 'eslint-plugin-vue'
import vuejsAccessibility from 'eslint-plugin-vuejs-accessibility'
import eslintPluginUnicorn from 'eslint-plugin-unicorn'
Expand All @@ -12,13 +13,14 @@ import jsdoc from 'eslint-plugin-jsdoc'
import stylistic from '@stylistic/eslint-plugin'
import eslintPluginImportX from 'eslint-plugin-import-x'
import eslintPluginN from 'eslint-plugin-n'
import eslintPluginPlaywright from 'eslint-plugin-playwright'
import eslintPluginPromise from 'eslint-plugin-promise'

import freetube from './_scripts/eslint-rules/plugin.mjs'

import activeLocales from './static/locales/activeLocales.json' with { type: 'json' }

export default [
export default defineConfig([
Comment thread
absidue marked this conversation as resolved.
{
ignores: [
'build/',
Expand Down Expand Up @@ -436,7 +438,7 @@ export default [
}
},
{
files: ['_scripts/**/*.mjs'],
files: ['_scripts/**/*.mjs', 'tests/**/*.mjs'],
languageOptions: {
globals: globals.node,
ecmaVersion: 'latest',
Expand All @@ -456,5 +458,24 @@ export default [
'unicorn/prefer-date-now': 'error',
'unicorn/prefer-array-index-of': 'error',
}
},
{
files: ['tests/playwright/helpers.mjs', 'tests/playwright/**/*spec.mjs'],
extends: [eslintPluginPlaywright.configs['flat/recommended']],
settings: {
playwright: {
globalAliases: {
test: ["electronDesktopTest", "electronMobileTest", "electronTabletTest"],
}
}
},
rules: {
"playwright/expect-expect": [
"error",
{
"assertFunctionNames": ["validateAccessibility"],
}
]
}
}
]
])
13 changes: 10 additions & 3 deletions package.json
Comment thread
radmorecameron marked this conversation as resolved.
Comment thread
radmorecameron marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
"lint-all": "run-p lint lint-json",
"lint": "run-p eslint-lint lint-style",
"lint-fix": "run-p eslint-lint-fix lint-style-fix",
"eslint-lint": "eslint --config eslint.config.mjs \"src/**/*.js\" \"src/renderer/**/*.vue\" \"static/*.js\" \"_scripts/*.js\" \"_scripts/**/*.mjs\"",
"eslint-lint-fix": "eslint --config eslint.config.mjs --fix \"src/**/*.js\" \"src/renderer/**/*.vue\" \"static/*.js\" \"_scripts/*.js\" \"_scripts/**/*.mjs\"",
"eslint-lint": "eslint --config eslint.config.mjs \"src/**/*.js\" \"src/renderer/**/*.vue\" \"static/*.js\" \"_scripts/*.js\" \"_scripts/**/*.mjs\" \"tests/**/*.mjs\"",
"eslint-lint-fix": "eslint --config eslint.config.mjs --fix \"src/**/*.js\" \"src/renderer/**/*.vue\" \"static/*.js\" \"_scripts/*.js\" \"_scripts/**/*.mjs\" \"tests/**/*.mjs\"",
"lint-json": "eslint --config eslint.config.mjs \"static/**/*.json\"",
"lint-style": "stylelint \"src/**/*.{css,scss}\"",
"lint-style-fix": "stylelint --fix \"src/**/*.{css,scss}\"",
Expand All @@ -44,10 +44,14 @@
"pack:main": "webpack --mode=production --config-node-env=production --config _scripts/webpack.main.config.js",
"pack:renderer": "webpack --mode=production --config-node-env=production --config _scripts/webpack.renderer.config.js",
"pack:preload": "webpack --mode=production --config-node-env=production --config _scripts/webpack.preload.config.js",
"pack:tests": "run-p pack:main-tests pack:renderer pack:preload pack:botGuardScript && node _scripts/injectAllowedPaths.mjs",
"pack:main-tests": "webpack --mode=production --config-node-env=production --env \"IS_TESTS=true\" --config _scripts/webpack.main.config.js",
"pack:web": "webpack --mode=production --config-node-env=production --config _scripts/webpack.web.config.js",
"pack:botGuardScript": "webpack --config _scripts/webpack.botGuardScript.config.js",
"checkforbadtemplates": "node _scripts/findMissingTemplates.mjs",
"ci": "yarn install --silent --frozen-lockfile --network-concurrency 1"
"ci": "yarn install --silent --frozen-lockfile --network-concurrency 1",
"test:playwright": "run-s pack:tests test:playwright-nopack",
"test:playwright-nopack": "playwright test"
Comment thread
radmorecameron marked this conversation as resolved.
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^7.2.0",
Expand All @@ -73,11 +77,13 @@
"youtubei.js": "^17.0.1"
},
"devDependencies": {
"@axe-core/playwright": "^4.11.1",
"@babel/core": "^7.29.0",
"@babel/preset-env": "^7.29.2",
"@double-great/stylelint-a11y": "^3.4.9",
"@eslint/js": "^10.0.1",
"@intlify/eslint-plugin-vue-i18n": "^4.3.0",
"@playwright/test": "^1.58.2",
"@stylistic/eslint-plugin": "^5.10.0",
"babel-loader": "^10.1.1",
"copy-webpack-plugin": "^14.0.0",
Expand All @@ -90,6 +96,7 @@
"eslint-plugin-jsdoc": "^62.9.0",
"eslint-plugin-jsonc": "^3.1.2",
"eslint-plugin-n": "^17.24.0",
"eslint-plugin-playwright": "^2.5.1",
"eslint-plugin-promise": "^7.2.1",
"eslint-plugin-unicorn": "^64.0.0",
"eslint-plugin-vue": "^10.8.0",
Expand Down
7 changes: 7 additions & 0 deletions playwright.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @type {import('@playwright/test').PlaywrightTestConfig} */
export default {
testDir: './tests/playwright',
testMatch: '*.spec.mjs',
workers: 1,
fullyParallel: false
}
1 change: 1 addition & 0 deletions src/datastores/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function createDatastore(name) {
return new Datastore({
filename: dbPath(name),
autoload: !process.env.IS_ELECTRON_MAIN,
inMemoryOnly: !!process.env.IS_TESTS,
// Automatically clean up corrupted data, instead of crashing
corruptAlertThreshold: 1
})
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/components/TopNav/TopNav.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
<button
v-if="!hideSearchBar"
class="navSearchButton navButton"
:aria-label="t('Search Bar.Open Search Container')"
:title="t('Search Bar.Open Search Container')"
@click="toggleSearchContainer"
>
<FontAwesomeIcon
Expand Down
1 change: 1 addition & 0 deletions static/locales/en-US.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Search / Go to URL: Search / Go to URL
Search Bar:
Clear Input: Clear Input
Remove: Remove
Open Search Container: Open Search Container
Search character limit: Search query is over the {searchCharacterLimit} character limit
Search Listing:
Label:
Expand Down
59 changes: 59 additions & 0 deletions tests/playwright/helpers.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { devices, expect, test, _electron as electron } from '@playwright/test'
import { join } from 'path'
import { AxeBuilder } from '@axe-core/playwright'

const mainJs = join(import.meta.dirname, '../../dist/main.js')

/**
*
* @param {string} name
* @param {import('@playwright/test').ViewportSize} viewPortSize
* @param {(function({ app: import('@playwright/test').ElectronApplication, page: import('@playwright/test').Page }) : Promise<void>)} func
*/
const electronTest = async (name, viewPortSize, func) => {
// eslint-disable-next-line playwright/expect-expect, playwright/valid-title
test(name, async () => {
const electronApp = await electron.launch({ args: [mainJs] })
const page = await electronApp.firstWindow()
page.setViewportSize(viewPortSize)

await func({ app: electronApp, page })

await electronApp.close()
})
}

/**
* @param {string} name
* @param {(function({ app: import('@playwright/test').ElectronApplication, page: import('@playwright/test').Page }) : Promise<void>)} func
*/
export const electronDesktopTest = async (name, func) => {
await electronTest(name, devices['Desktop Chrome'].viewport, func)
}

/**
* @param {string} name
* @param {(function({ app: import('@playwright/test').ElectronApplication, page: import('@playwright/test').Page }) : Promise<void>)} func
*/
export const electronMobileTest = async (name, func) => {
await electronTest(name, devices['LG Optimus L70'].viewport, func)
}

/**
* @param {string} name
* @param {(function({ app: import('@playwright/test').ElectronApplication, page: import('@playwright/test').Page }) : Promise<void>)} func
*/
export const electronTabletTest = async (name, func) => {
await electronTest(name, devices['Galaxy Tab S9'].viewport, func)
}

/**
* @param {import('@playwright/test').Page} page
*/
export async function validateAccessibility (page) {
const axeResults = await new AxeBuilder({ page })
.setLegacyMode(true)
.analyze()

expect(axeResults.violations).toHaveLength(0)
}
Loading
Loading