diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 143aab2ab4c..48620686c46 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -28,7 +28,7 @@ permissions: jobs: build: if: github.event_name == 'pull_request' || github.repository != 'discourse/discourse-private-mirror' - name: ${{ matrix.target }} ${{ matrix.build_type }} # Update fetch-job-id step if changing this + name: ${{ matrix.target }} ${{ matrix.build_type }}${{ (matrix.target == 'core' && matrix.build_type == 'frontend' && format(' ({0})', matrix.browser)) || '' }} # Update fetch-job-id step if changing this runs-on: ${{ (github.repository_owner == 'discourse' && 'debian-12') || 'ubuntu-latest' }} container: discourse/discourse_test:release timeout-minutes: 20 @@ -42,8 +42,9 @@ jobs: MINIO_RUNNER_LOG_LEVEL: DEBUG DISCOURSE_TURBO_RSPEC_RETRY_AND_LOG_FLAKY_TESTS: ${{ (matrix.build_type == 'system' || matrix.build_type == 'backend') && '1' }} CHEAP_SOURCE_MAPS: "1" - TESTEM_DEFAULT_BROWSER: Chrome MINIO_RUNNER_INSTALL_DIR: /home/discourse/.minio_runner + TESTEM_BROWSER: ${{ (startsWith(matrix.browser, 'Firefox') && 'Firefox') || matrix.browser }} + TESTEM_FIREFOX_PATH: ${{ (matrix.browser == 'Firefox Evergreen') && '/opt/firefox-evergreen/firefox' }} strategy: fail-fast: false @@ -51,6 +52,7 @@ jobs: matrix: build_type: [backend, frontend, system, annotations] target: [core, plugins, themes] + browser: [Chrome] exclude: - build_type: annotations target: plugins @@ -58,11 +60,15 @@ jobs: target: themes - build_type: backend target: themes - - build_type: frontend - target: core # Handled by core_frontend_tests job (below) include: - build_type: system target: chat + - build_type: frontend + target: core + browser: Firefox Evergreen + - build_type: frontend + target: core + browser: Firefox ESR steps: - name: Set working directory owner @@ -233,6 +239,11 @@ jobs: if: matrix.build_type == 'backend' && matrix.target == 'plugins' run: bin/rake plugin:turbo_spec['*','--verbose --format=documentation --use-runtime-info --profile=50'] + - name: Core QUnit + if: matrix.build_type == 'frontend' && matrix.target == 'core' + run: QUNIT_WRITE_EXECUTION_FILE=1 bin/rake qunit:test + timeout-minutes: 30 + - name: Plugin QUnit if: matrix.build_type == 'frontend' && matrix.target == 'plugins' run: QUNIT_WRITE_EXECUTION_FILE=1 bin/rake plugin:qunit['*'] @@ -244,9 +255,9 @@ jobs: timeout-minutes: 10 - uses: actions/upload-artifact@v4 - if: always() && matrix.build_type == 'frontend' && matrix.target == 'plugins' + if: always() && matrix.build_type == 'frontend' with: - name: ember-exam-execution-plugins-frontend-${{ hashFiles('./app/assets/javascripts/discourse/test-execution-*.json') }} + name: ember-exam-execution-${{ matrix.target }}-${{ matrix.browser }}-frontend-${{ hashFiles('./app/assets/javascripts/discourse/test-execution-*.json') }} path: ./app/assets/javascripts/discourse/test-execution-*.json - name: Ember Build for System Tests @@ -322,7 +333,7 @@ jobs: id: fetch-job-id if: steps.check-flaky-spec-report.outputs.exists == 'true' run: | - job_id=$(ruby script/get_github_workflow_run_job_id.rb ${{ github.run_id }} ${{ github.run_attempt }} '${{ matrix.target }} ${{ matrix.build_type }}') + job_id=$(ruby script/get_github_workflow_run_job_id.rb ${{ github.run_id }} ${{ github.run_attempt }} '${{ matrix.target }} ${{ matrix.build_type }}${{ (matrix.target == 'core' && matrix.build_type == 'frontend' && format(' ({0})', matrix.browser)) || '' }}') echo "job_id=$job_id" >> $GITHUB_OUTPUT - name: Create flaky tests report artifact @@ -353,56 +364,6 @@ jobs: fi timeout-minutes: 30 - core_frontend_tests: - if: github.event_name == 'pull_request' || github.repository != 'discourse/discourse-private-mirror' - name: core frontend (${{ matrix.browser }}) - runs-on: ${{ (github.repository_owner == 'discourse' && 'debian-12') || 'ubuntu-latest' }} - container: - image: discourse/discourse_test:release - options: --user discourse - - timeout-minutes: 35 - - strategy: - fail-fast: false - matrix: - browser: ["Chrome", "Firefox ESR", "Firefox Evergreen"] - - env: - TESTEM_BROWSER: ${{ (startsWith(matrix.browser, 'Firefox') && 'Firefox') || matrix.browser }} - TESTEM_FIREFOX_PATH: ${{ (matrix.browser == 'Firefox Evergreen') && '/opt/firefox-evergreen/firefox' }} - CHEAP_SOURCE_MAPS: "1" - - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - name: Setup Git - run: | - git config --global user.email "ci@ci.invalid" - git config --global user.name "Discourse CI" - - - name: pnpm install - run: pnpm install --frozen-lockfile - - - name: Ember Build - working-directory: ./app/assets/javascripts/discourse - run: | - mkdir /tmp/emberbuild - pnpm ember build --environment=test -o /tmp/emberbuild - - - name: Core QUnit - working-directory: ./app/assets/javascripts/discourse - run: | - pnpm ember exam --path /tmp/emberbuild --load-balance --parallel=$(($(nproc) / 2)) --launch "${{ env.TESTEM_BROWSER }}" --write-execution-file --random - timeout-minutes: 15 - - - uses: actions/upload-artifact@v4 - if: ${{ always() }} - with: - name: ember-exam-execution-${{ matrix.browser }}-${{ hashFiles('./app/assets/javascripts/discourse/test-execution-*.json') }} - path: ./app/assets/javascripts/discourse/test-execution-*.json merge: if: github.repository == 'discourse/discourse' && github.ref == 'refs/heads/main' diff --git a/app/assets/javascripts/discourse/ember-cli-build.js b/app/assets/javascripts/discourse/ember-cli-build.js index dd1cfaf6368..44cac1ad74b 100644 --- a/app/assets/javascripts/discourse/ember-cli-build.js +++ b/app/assets/javascripts/discourse/ember-cli-build.js @@ -4,9 +4,7 @@ const EmberApp = require("ember-cli/lib/broccoli/ember-app"); const path = require("path"); const mergeTrees = require("broccoli-merge-trees"); const concat = require("broccoli-concat"); -const { createI18nTree } = require("./lib/translation-plugin"); const { parsePluginClientSettings } = require("./lib/site-settings-plugin"); -const discourseScss = require("./lib/discourse-scss"); const generateScriptsTree = require("./lib/scripts"); const funnel = require("broccoli-funnel"); const DeprecationSilencer = require("deprecation-silencer"); @@ -96,20 +94,12 @@ module.exports = function (defaults) { const adminTree = app.project.findAddonByName("admin").treeForAddonBundle(); - const testStylesheetTree = mergeTrees([ - discourseScss(`${discourseRoot}/app/assets/stylesheets`, "qunit.scss"), - discourseScss( - `${discourseRoot}/app/assets/stylesheets`, - "qunit-custom.scss" - ), - ]); app.project.liveReloadFilterPatterns = [/.*\.scss/]; const terserPlugin = app.project.findAddonByName("ember-cli-terser"); const applyTerser = (tree) => terserPlugin.postprocessTree("all", tree); let extraPublicTrees = [ - createI18nTree(discourseRoot, vendorJs), parsePluginClientSettings(discourseRoot, vendorJs, app), funnel(`${discourseRoot}/public/javascripts`, { destDir: "javascripts" }), applyTerser( @@ -120,7 +110,6 @@ module.exports = function (defaults) { ), applyTerser(generateScriptsTree(app)), applyTerser(discoursePluginsTree), - testStylesheetTree, ]; const assetCachebuster = process.env["DISCOURSE_ASSET_URL_SALT"] || ""; diff --git a/app/assets/javascripts/discourse/lib/discourse-scss.js b/app/assets/javascripts/discourse/lib/discourse-scss.js deleted file mode 100644 index a96881dafe7..00000000000 --- a/app/assets/javascripts/discourse/lib/discourse-scss.js +++ /dev/null @@ -1,64 +0,0 @@ -const Plugin = require("broccoli-plugin"); -const sass = require("sass"); -const fs = require("fs"); -const concat = require("broccoli-concat"); - -let builtSet = new Set(); - -class DiscourseScss extends Plugin { - constructor(inputNodes, inputFile, options) { - super(inputNodes, { - ...options, - persistentOutput: true, - }); - - this.inputFile = inputFile; - } - - build() { - let file = this.inputPaths[0] + "/" + this.inputFile; - - // We could get fancy eventually and do this based on whether the css changes - // but this is just used for tests right now. - if (builtSet.has(file)) { - return; - } - - let deprecationCount = 0; - let result = sass.renderSync({ - file, - includePaths: this.inputPaths, - silenceDeprecations: ["color-functions", "import", "global-builtin"], - verbose: true, // call warn() for all deprecations - logger: { - warn(message, options) { - if (options.deprecation) { - deprecationCount += 1; - } else { - // eslint-disable-next-line no-console - console.warn(`\nWARNING: ${message}`); - } - }, - }, - }); - if (deprecationCount > 0) { - // eslint-disable-next-line no-console - console.warn( - `\nWARNING: ${deprecationCount} deprecations encountered while compiling scss. (we cannot correct these until the Ruby SCSS pipeline is updated)` - ); - } - - fs.writeFileSync( - `${this.outputPath}/` + this.inputFile.replace(".scss", ".css"), - result.css - ); - - builtSet.add(file); - } -} - -module.exports = function scss(path, file) { - return concat(new DiscourseScss([path], file), { - outputFile: `assets/${file.replace(".scss", ".css")}`, - }); -}; diff --git a/app/assets/javascripts/discourse/lib/translation-plugin.js b/app/assets/javascripts/discourse/lib/translation-plugin.js deleted file mode 100644 index ef626bdf1be..00000000000 --- a/app/assets/javascripts/discourse/lib/translation-plugin.js +++ /dev/null @@ -1,137 +0,0 @@ -const Plugin = require("broccoli-plugin"); -const Yaml = require("js-yaml"); -const fs = require("fs"); -const concat = require("broccoli-concat"); -const mergeTrees = require("broccoli-merge-trees"); -const MessageFormat = require("@messageformat/core"); -const deepmerge = require("deepmerge"); -const glob = require("glob"); -const { shouldLoadPlugins } = require("discourse-plugins"); - -let built = false; - -class TranslationPlugin extends Plugin { - constructor(inputNodes, inputFile, options) { - super(inputNodes, { - ...options, - persistentOutput: true, - }); - - this.inputFile = inputFile; - } - - replaceMF(formats, input, path = []) { - if (!input) { - return; - } - - Object.keys(input).forEach((key) => { - let value = input[key]; - - let subpath = path.concat(key); - if (typeof value === "object") { - this.replaceMF(formats, value, subpath); - } else if (key.endsWith("_MF")) { - // omit locale.js - let mfPath = subpath.slice(2).join("."); - formats[mfPath] = this.mf.compile(value); - } - }); - } - - build() { - // We could get fancy eventually and do this based on whether the yaml - // or vendor files change but in practice we shouldn't need exact up to date - // translations in admin. - if (built) { - return; - } - - let parsed = {}; - - this.inputPaths.forEach((path) => { - let file = path + "/" + this.inputFile; - let yaml = fs.readFileSync(file, { encoding: "UTF-8" }); - let loaded = Yaml.load(yaml, { json: true }); - parsed = deepmerge(parsed, loaded); - }); - - let extras = { - en: { - admin: parsed.en.admin_js.admin, - wizard: parsed.en.wizard_js.wizard, - }, - }; - - delete parsed.en.admin_js; - delete parsed.en.wizard_js; - - let formats = {}; - this.mf = new MessageFormat("en"); - this.replaceMF(formats, parsed); - this.replaceMF(formats, extras); - - formats = Object.entries(formats).map(([k, v]) => `"${k}": ${v}`); - - let contents = ` - (function() { - I18n.locale = 'en'; - I18n.translations = ${JSON.stringify(parsed)}; - I18n.extras = ${JSON.stringify(extras)}; - - const Messages = require("@messageformat/runtime/messages").default; - const { number, plural, select } = require("@messageformat/runtime"); - const { en } = require("@messageformat/runtime/lib/cardinals"); - const msgData = { en: { ${formats.join(",\n")} } }; - const messages = new Messages(msgData, "en"); - messages.defaultLocale = "en"; - I18n._mfMessages = messages; - })() - `; - - fs.writeFileSync( - `${this.outputPath}/` + this.inputFile.replace(".yml", ".js"), - contents - ); - built = true; - } -} - -module.exports = function translatePlugin(...params) { - return new TranslationPlugin(...params); -}; - -module.exports.createI18nTree = function (discourseRoot, vendorJs) { - let translations = [discourseRoot + "/config/locales"]; - - if (shouldLoadPlugins()) { - translations = translations.concat( - glob - .sync(discourseRoot + "/plugins/*/config/locales/client.en.yml") - .map((f) => f.replace(/\/client\.en\.yml$/, "")) - ); - } - - let en = new TranslationPlugin(translations, "client.en.yml"); - - return concat( - mergeTrees([ - vendorJs, - discourseRoot + "/app/assets/javascripts/locales", - en, - ]), - { - inputFiles: [ - "i18n.js", - "moment.js", - "moment-timezone-with-data.js", - "client.en.js", - ], - headerFiles: ["i18n.js", "moment.js", "moment-timezone-with-data.js"], - footerFiles: ["client.en.js"], - outputFile: `assets/test-i18n.js`, - } - ); -}; - -module.exports.TranslationPlugin = TranslationPlugin; diff --git a/app/assets/javascripts/discourse/package.json b/app/assets/javascripts/discourse/package.json index bf8070e2716..55374884ff7 100644 --- a/app/assets/javascripts/discourse/package.json +++ b/app/assets/javascripts/discourse/package.json @@ -127,7 +127,6 @@ "pretender": "^3.4.7", "qunit": "^2.24.1", "qunit-dom": "^3.4.0", - "sass": "^1.85.0", "select-kit": "workspace:1.0.0", "sinon": "^19.0.2", "source-map": "^0.7.4", diff --git a/app/assets/javascripts/discourse/testem.js b/app/assets/javascripts/discourse/testem.js index d30c4910057..ac54dc31423 100644 --- a/app/assets/javascripts/discourse/testem.js +++ b/app/assets/javascripts/discourse/testem.js @@ -1,5 +1,4 @@ const TapReporter = require("testem/lib/reporters/tap_reporter"); -const { shouldLoadPlugins } = require("discourse-plugins"); const fs = require("fs"); const displayUtils = require("testem/lib/utils/displayutils"); const colors = require("@colors/colors/safe"); @@ -177,6 +176,16 @@ if (process.env.TESTEM_FIREFOX_PATH) { } const target = `http://127.0.0.1:${process.env.UNICORN_PORT || "3000"}`; + +fetch(`${target}/about.json`).catch(() => { + // eslint-disable-next-line no-console + console.error( + colors.red( + `Error connecting to Rails server on ${target}. Is it running? Use 'bin/rake qunit:test' or 'plugin:qunit' to start automatically.` + ) + ); +}); + const themeTestPages = process.env.THEME_TEST_PAGES; if (themeTestPages) { @@ -204,20 +213,26 @@ if (themeTestPages) { }); }, ]; -} else if (shouldLoadPlugins()) { +} else { // Running with ember cli, but we want to pass through plugin request to Rails module.exports.proxies = { + "/assets/locales/*.js": { + target, + }, "/assets/plugins/*_extra.js": { target, }, "/plugins/": { target, }, - "/bootstrap/plugin-css-for-tests.css": { + "/bootstrap/": { target, }, "/stylesheets/": { target, }, + "/extra-locales/": { + target, + }, }; } diff --git a/app/assets/javascripts/discourse/tests/index.html b/app/assets/javascripts/discourse/tests/index.html index 3ff46ac2e85..3d88c4a1340 100644 --- a/app/assets/javascripts/discourse/tests/index.html +++ b/app/assets/javascripts/discourse/tests/index.html @@ -20,7 +20,7 @@ - + {{content-for "head-footer"}} {{content-for "test-head-footer"}} @@ -53,7 +53,10 @@ - + + + + @@ -72,6 +75,6 @@ - + diff --git a/app/assets/stylesheets/qunit.scss b/app/assets/stylesheets/qunit.scss deleted file mode 100644 index cd79425feb8..00000000000 --- a/app/assets/stylesheets/qunit.scss +++ /dev/null @@ -1,11 +0,0 @@ -// Styles for Ember CLI test environment -:root { - --font-family: "Arial"; -} - -@import "common/foundation/colors"; -@import "common/foundation/variables"; -@import "common/foundation/mixins"; -@import "desktop"; -@import "color_definitions"; -@import "admin"; diff --git a/app/controllers/bootstrap_controller.rb b/app/controllers/bootstrap_controller.rb index 4770ee17cc2..cb4eadc6dd6 100644 --- a/app/controllers/bootstrap_controller.rb +++ b/app/controllers/bootstrap_controller.rb @@ -4,16 +4,26 @@ class BootstrapController < ApplicationController skip_before_action :redirect_to_login_if_required, :check_xhr def plugin_css_for_tests + targets = Discourse.find_plugin_css_assets(include_disabled: true, desktop_view: true) + render_css_for_tests(targets) + end + + def core_css_for_tests + targets = %w[color_definitions desktop admin] + render_css_for_tests(targets) + end + + private + + def render_css_for_tests(targets) urls = - Discourse - .find_plugin_css_assets(include_disabled: true, desktop_view: true) - .map do |target| - details = Stylesheet::Manager.new().stylesheet_details(target, "all") - details[0][:new_href] - end + targets.map do |target| + details = Stylesheet::Manager.new().stylesheet_details(target, "all") + details[0][:new_href] + end stylesheet = <<~CSS - /* For use in tests only - `@import`s all plugin stylesheets */ + /* For use in tests only */ #{urls.map { |url| "@import \"#{url}\";" }.join("\n")} CSS diff --git a/app/controllers/extra_locales_controller.rb b/app/controllers/extra_locales_controller.rb index df2768e8099..1b5fc059514 100644 --- a/app/controllers/extra_locales_controller.rb +++ b/app/controllers/extra_locales_controller.rb @@ -85,6 +85,7 @@ class ExtraLocalesController < ApplicationController private def valid_bundle?(bundle) - bundle.in?(BUNDLES) || (bundle =~ /\A(admin|wizard)\z/ && current_user&.staff?) + return true if bundle.in?(BUNDLES) + bundle =~ /\A(admin|wizard)\z/ && (current_user&.staff? || Rails.env.local?) end end diff --git a/config/routes.rb b/config/routes.rb index 5ab67c8d219..75e5ed6bfbb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -29,6 +29,7 @@ Discourse::Application.routes.draw do if Rails.env.test? || Rails.env.development? get "/bootstrap/plugin-css-for-tests.css" => "bootstrap#plugin_css_for_tests" + get "/bootstrap/core-css-for-tests.css" => "bootstrap#core_css_for_tests" end # This is not a valid production route and is causing routing errors to be raised in diff --git a/lib/tasks/docker.rake b/lib/tasks/docker.rake index cb1a6021dcd..4269a6e0ac6 100644 --- a/lib/tasks/docker.rake +++ b/lib/tasks/docker.rake @@ -300,10 +300,7 @@ task "docker:test" do unless ENV["RUBY_ONLY"] unless ENV["SKIP_CORE"] - @good &&= - run_or_fail( - "cd app/assets/javascripts/discourse && CI=1 pnpm ember exam --load-balance --parallel=#{qunit_concurrency} --random", - ) + @good &&= run_or_fail("CI=1 QUNIT_PARALLEL=#{qunit_concurrency} bin/rake qunit:test") end unless ENV["SKIP_PLUGINS"] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7603dfc39c6..ae5188c1cfc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -597,9 +597,6 @@ importers: qunit-dom: specifier: ^3.4.0 version: 3.4.0 - sass: - specifier: ^1.85.0 - version: 1.85.0 select-kit: specifier: workspace:1.0.0 version: link:../select-kit @@ -2423,88 +2420,6 @@ packages: resolution: {integrity: sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==} engines: {node: ^16.14.0 || >=18.0.0} - '@parcel/watcher-android-arm64@2.5.1': - resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [android] - - '@parcel/watcher-darwin-arm64@2.5.1': - resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [darwin] - - '@parcel/watcher-darwin-x64@2.5.1': - resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [darwin] - - '@parcel/watcher-freebsd-x64@2.5.1': - resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [freebsd] - - '@parcel/watcher-linux-arm-glibc@2.5.1': - resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - - '@parcel/watcher-linux-arm-musl@2.5.1': - resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - - '@parcel/watcher-linux-arm64-glibc@2.5.1': - resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - - '@parcel/watcher-linux-arm64-musl@2.5.1': - resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - - '@parcel/watcher-linux-x64-glibc@2.5.1': - resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - - '@parcel/watcher-linux-x64-musl@2.5.1': - resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - - '@parcel/watcher-win32-arm64@2.5.1': - resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [win32] - - '@parcel/watcher-win32-ia32@2.5.1': - resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} - engines: {node: '>= 10.0.0'} - cpu: [ia32] - os: [win32] - - '@parcel/watcher-win32-x64@2.5.1': - resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [win32] - - '@parcel/watcher@2.5.1': - resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} - engines: {node: '>= 10.0.0'} - '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -3612,10 +3527,6 @@ packages: peerDependencies: chart.js: '>=3.0.0' - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} @@ -4238,11 +4149,6 @@ packages: resolution: {integrity: sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==} engines: {node: '>=12.20'} - detect-libc@1.0.3: - resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} - engines: {node: '>=0.10'} - hasBin: true - detect-newline@4.0.1: resolution: {integrity: sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -5515,9 +5421,6 @@ packages: immer@10.1.1: resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==} - immutable@5.0.3: - resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==} - import-cwd@3.0.0: resolution: {integrity: sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==} engines: {node: '>=8'} @@ -6594,9 +6497,6 @@ packages: no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} - node-addon-api@7.1.1: - resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} @@ -7325,10 +7225,6 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} - recast@0.18.10: resolution: {integrity: sha512-XNvYvkfdAN9QewbrxeTOjgINkdY/odTgTS56ZNEWL9Ml0weT4T3sFtvnTuF+Gxyu46ANcRm1ntrF6F5LAJPAaQ==} engines: {node: '>= 4'} @@ -7592,11 +7488,6 @@ packages: engines: {node: 10.* || >= 12.*} hasBin: true - sass@1.85.0: - resolution: {integrity: sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww==} - engines: {node: '>=14.0.0'} - hasBin: true - saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -10598,67 +10489,6 @@ snapshots: - bluebird - supports-color - '@parcel/watcher-android-arm64@2.5.1': - optional: true - - '@parcel/watcher-darwin-arm64@2.5.1': - optional: true - - '@parcel/watcher-darwin-x64@2.5.1': - optional: true - - '@parcel/watcher-freebsd-x64@2.5.1': - optional: true - - '@parcel/watcher-linux-arm-glibc@2.5.1': - optional: true - - '@parcel/watcher-linux-arm-musl@2.5.1': - optional: true - - '@parcel/watcher-linux-arm64-glibc@2.5.1': - optional: true - - '@parcel/watcher-linux-arm64-musl@2.5.1': - optional: true - - '@parcel/watcher-linux-x64-glibc@2.5.1': - optional: true - - '@parcel/watcher-linux-x64-musl@2.5.1': - optional: true - - '@parcel/watcher-win32-arm64@2.5.1': - optional: true - - '@parcel/watcher-win32-ia32@2.5.1': - optional: true - - '@parcel/watcher-win32-x64@2.5.1': - optional: true - - '@parcel/watcher@2.5.1': - dependencies: - detect-libc: 1.0.3 - is-glob: 4.0.3 - micromatch: 4.0.8 - node-addon-api: 7.1.1 - optionalDependencies: - '@parcel/watcher-android-arm64': 2.5.1 - '@parcel/watcher-darwin-arm64': 2.5.1 - '@parcel/watcher-darwin-x64': 2.5.1 - '@parcel/watcher-freebsd-x64': 2.5.1 - '@parcel/watcher-linux-arm-glibc': 2.5.1 - '@parcel/watcher-linux-arm-musl': 2.5.1 - '@parcel/watcher-linux-arm64-glibc': 2.5.1 - '@parcel/watcher-linux-arm64-musl': 2.5.1 - '@parcel/watcher-linux-x64-glibc': 2.5.1 - '@parcel/watcher-linux-x64-musl': 2.5.1 - '@parcel/watcher-win32-arm64': 2.5.1 - '@parcel/watcher-win32-ia32': 2.5.1 - '@parcel/watcher-win32-x64': 2.5.1 - optional: true - '@pkgjs/parseargs@0.11.0': optional: true @@ -12139,10 +11969,6 @@ snapshots: dependencies: chart.js: 3.5.1 - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - chownr@2.0.0: {} chrome-launcher@1.1.2: @@ -12580,9 +12406,6 @@ snapshots: detect-indent@7.0.1: {} - detect-libc@1.0.3: - optional: true - detect-newline@4.0.1: {} devtools-protocol@0.0.1402036: {} @@ -14665,8 +14488,6 @@ snapshots: immer@10.1.1: {} - immutable@5.0.3: {} - import-cwd@3.0.0: dependencies: import-from: 3.0.0 @@ -15768,9 +15589,6 @@ snapshots: lower-case: 2.0.2 tslib: 2.8.1 - node-addon-api@7.1.1: - optional: true - node-domexception@1.0.0: {} node-fetch@2.7.0(encoding@0.1.13): @@ -16566,8 +16384,6 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - readdirp@4.1.2: {} - recast@0.18.10: dependencies: ast-types: 0.13.3 @@ -16838,14 +16654,6 @@ snapshots: minimist: 1.2.8 walker: 1.0.8 - sass@1.85.0: - dependencies: - chokidar: 4.0.3 - immutable: 5.0.3 - source-map-js: 1.2.1 - optionalDependencies: - '@parcel/watcher': 2.5.1 - saxes@6.0.0: dependencies: xmlchars: 2.2.0 diff --git a/spec/requests/extra_locales_controller_spec.rb b/spec/requests/extra_locales_controller_spec.rb index c240c293f74..be4c910b2ee 100644 --- a/spec/requests/extra_locales_controller_spec.rb +++ b/spec/requests/extra_locales_controller_spec.rb @@ -14,7 +14,8 @@ RSpec.describe ExtraLocalesController do expect(response.status).to eq(403) end - it "requires staff access" do + it "requires staff access in production" do + Rails.env.stubs(:local?).returns(false) get "/extra-locales/admin" expect(response.status).to eq(403)