diff --git a/.github/workflows/a11y_tests.yaml b/.github/workflows/a11y_tests.yaml index 5f22a951d..5fd36e754 100644 --- a/.github/workflows/a11y_tests.yaml +++ b/.github/workflows/a11y_tests.yaml @@ -1,15 +1,18 @@ name: Accessibility (a11y) Tests on: - pull_request: + push: + branches: + - master +# pull_request: jobs: a11y_tests: strategy: fail-fast: false matrix: - php-version: ['7.2'] - node-version: ['12.5'] + php-version: ['8.0'] + node-version: ['12.22'] actions: - name: Run pa11yci @@ -19,38 +22,43 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # see https://github.com/actions/starter-workflows/blob/main/ci/node.js.yml - - name: Use Node.js 12.5 - uses: actions/setup-node@v1 + name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - coverage: none - - uses: shivammathur/setup-php@v2 +# coverage: none + - name: Use PHP ${{ matrix.php-version }} + uses: shivammathur/setup-php@v2 with: # test the lowest version, to make sure checks pass on it php-version: ${{ matrix.php-version }} extensions: json, mbstring, pdo, curl, pdo_sqlite coverage: none + tools: composer + - run: | + wget https://get.symfony.com/cli/installer -O - | bash - name: Install dependencies run: | - sudo composer self-update -q - sudo COMPOSER_MEMORY_LIMIT=-1 COMPOSER_PROCESS_TIMEOUT=60 composer update --prefer-dist --no-progress - ./bin/console bolt:info --ansi + export PATH="$HOME/.symfony5/bin:$PATH" + COMPOSER_MEMORY_LIMIT=-1 COMPOSER_PROCESS_TIMEOUT=60 composer update --prefer-dist --no-progress + symfony console bolt:info --ansi npm set progress=false npm ci - name: Prepare environment run: | + export PATH="$HOME/.symfony5/bin:$PATH" # build assets npm run build sudo chmod -R 777 config/ public/files/ public/theme/ public/thumbs/ var/ # prepare web server for e2e tests - ./bin/console doctrine:database:create - ./bin/console doctrine:schema:create - ./bin/console doctrine:fixtures:load --group=without-images -n - ./bin/console server:start 127.0.0.1:8088 + symfony console doctrine:database:create + symfony console doctrine:schema:create + symfony console doctrine:fixtures:load --group=without-images -n + symfony server:start --no-tls --port=8088 -d # test if web server works sleep 3 wget "http://127.0.0.1:8088/bolt/login" diff --git a/.github/workflows/api_tests.yaml b/.github/workflows/api_tests.yaml index 522f72c33..f889c1aa4 100644 --- a/.github/workflows/api_tests.yaml +++ b/.github/workflows/api_tests.yaml @@ -1,37 +1,45 @@ name: API tests on: - pull_request: + push: + branches: + - master +# pull_request: jobs: apicurltests: strategy: matrix: - php-version: [ '7.2', '8.0' ] + php-version: [ '8.0' ] name: curl tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 with: # test the lowest version, to make sure checks pass on it php-version: ${{ matrix.php-version }} extensions: json, mbstring, pdo, curl, pdo_sqlite coverage: none - - name: Initialise + tools: composer + - name: Symfony cli installation run: | - sudo composer self-update -q + wget https://get.symfony.com/cli/installer -O - | bash - name: Install dependencies run: | - sudo COMPOSER_MEMORY_LIMIT=-1 COMPOSER_PROCESS_TIMEOUT=60 composer update --prefer-dist --no-progress + export PATH="$HOME/.symfony5/bin:$PATH" + COMPOSER_MEMORY_LIMIT=-1 COMPOSER_PROCESS_TIMEOUT=60 symfony composer update --prefer-dist --no-progress - name: Initialise the database run: | - sudo chmod -R 777 config/ public/files/ public/theme/ public/thumbs/ var/ - ./bin/console doctrine:database:create - ./bin/console doctrine:schema:create - ./bin/console server:start 127.0.0.1:8088 + export PATH="$HOME/.symfony5/bin:$PATH" + chmod -R 777 config/ public/files/ public/theme/ public/thumbs/ var/ + symfony console doctrine:database:create + symfony console doctrine:schema:create + symfony server:start --no-tls --port=8088 -d - name: create api user - run: php bin/console bolt:add-user apiuser apiuser%1 api@example.org API --roles=ROLE_WEBSERVICE + run: | + export PATH="$HOME/.symfony5/bin:$PATH" + symfony console bolt:add-user apiuser apiuser%1 api@example.org API --roles=ROLE_WEBSERVICE - name: check API user gets content run: curl -fkI -u apiuser:apiuser%1 http://localhost:8088/api/contents - name: check API user gets fields diff --git a/.github/workflows/assets_code_analysis.yaml b/.github/workflows/assets_code_analysis.yaml index 44ec919dd..c6754313c 100644 --- a/.github/workflows/assets_code_analysis.yaml +++ b/.github/workflows/assets_code_analysis.yaml @@ -1,7 +1,7 @@ name: Assets Code Analysis on: - pull_request: null +# pull_request: null push: branches: - master @@ -24,14 +24,14 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # see https://github.com/actions/starter-workflows/blob/main/ci/node.js.yml - - name: Use Node.js 12.5 - uses: actions/setup-node@v1 + name: Use Node.js 12.22 + uses: actions/setup-node@v4 with: - node-version: 12.5 + node-version: 12.22 # same as "npm install", just uses package-lock.json", see https://stackoverflow.com/a/53325242/1348344 - run: npm ci diff --git a/.github/workflows/code_analysis.yaml b/.github/workflows/code_analysis.yaml index 5adff6dbf..0a95110da 100644 --- a/.github/workflows/code_analysis.yaml +++ b/.github/workflows/code_analysis.yaml @@ -1,7 +1,7 @@ name: Code Analysis on: - pull_request: null +# pull_request: null push: branches: - master @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - php-version: ['7.2', '8.0'] + php-version: ['8.0'] actions: - name: Coding Standard @@ -46,7 +46,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # see https://github.com/shivammathur/setup-php - uses: shivammathur/setup-php@v2 with: @@ -54,6 +54,7 @@ jobs: php-version: ${{ matrix.php-version }} extensions: json, mbstring, pdo, curl, pdo_sqlite coverage: none + tools: composer - run: composer install --no-progress --ansi diff --git a/.github/workflows/cypress_tests.yaml b/.github/workflows/cypress_tests.yaml index 57846d7ba..4a7b81e9f 100644 --- a/.github/workflows/cypress_tests.yaml +++ b/.github/workflows/cypress_tests.yaml @@ -16,55 +16,79 @@ jobs: matrix: containers: [1, 2, 3] # number of parallel containers steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 with: # test the lowest version, to make sure checks pass on it - php-version: 7.2 + php-version: 8.0 extensions: json, mbstring, pdo, curl, pdo_sqlite coverage: none - - uses: actions/setup-node@v1 + tools: composer + - uses: actions/setup-node@v4 with: - node-version: 12.5 + node-version: 12.22 # See https://github.community/t/sudo-apt-install-fails-with-failed-to-fetch-http-security-ubuntu-com-404-not-found-ip/17075 - - run: sudo apt update + - run: | + sudo apt update + - name: Symfony cli installation + run: | + wget https://get.symfony.com/cli/installer -O - | bash - name: Install dependencies run: | - sudo composer self-update -q - sudo COMPOSER_MEMORY_LIMIT=-1 COMPOSER_PROCESS_TIMEOUT=60 composer update --prefer-dist --no-progress - ./bin/console bolt:info --ansi + export PATH="$HOME/.symfony5/bin:$PATH" + COMPOSER_MEMORY_LIMIT=-1 COMPOSER_PROCESS_TIMEOUT=60 symfony composer update --prefer-dist --no-progress + symfony console bolt:info --ansi npm set progress=false npm ci mkdir -p ./var/log/e2e-reports/report/features/ touch ./var/log/e2e-reports/report/features/.gitkeep # Install latest stable Chrome for e2e tests sudo apt --fix-broken install - sudo apt-get install libxss1 libappindicator1 libindicator7 + #sudo apt-get install libxss1 libappindicator1 libindicator7 + sudo apt-cache search libappindicator1 + sudo apt-get install libxss1 libindicator7 wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb sudo apt install ./google-chrome*.deb - name: Prepare environment run: | + export PATH="$HOME/.symfony5/bin:$PATH" # build assets npm run build sudo chmod -R 777 config/ public/files/ public/theme/ public/thumbs/ var/ + echo "date.timezone=UTC" >> php.ini + echo "session.gc_probability=0" >> php.ini + echo "session.gc_divisor=100000" >> php.ini + echo "session.gc_maxlifetime=1440000" >> php.ini # prepare web server for e2e tests - ./bin/console doctrine:database:create - ./bin/console doctrine:schema:create - ./bin/console doctrine:fixtures:load --group=without-images -n - ./bin/console server:start 127.0.0.1:8088 + symfony console doctrine:database:create + symfony console doctrine:schema:create + symfony console doctrine:fixtures:load --group=without-images -n + symfony server:start --no-tls --port=8088 -d # test if web server works sleep 3 wget "http://127.0.0.1:8088/bolt/login" - name: Cypress run - uses: cypress-io/github-action@v2 + uses: cypress-io/github-action@v6 with: command: "npm run cypress:ci" + + # Starts web server for E2E tests - replace with your own server invocation + # https://docs.cypress.io/guides/continuous-integration/introduction#Boot-your-server +# start: npm start + wait-on: 'http://127.0.0.1:8088' # Waits for above + # Records to Cypress Cloud + # https://docs.cypress.io/guides/cloud/projects#Set-up-a-project-to-record + record: true + parallel: true env: CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} - GITHUB_TOKEN: ${{ secrets.CYPRESS_GITHUB_TOKEN }} - - uses: actions/upload-artifact@v1 + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ELECTRON_ENABLE_LOGGING: 1 + - uses: actions/upload-artifact@v4 if: failure() with: - name: cypress-screenshots - path: tests/cypress/screenshots + name: cypress-screenshots-${{matrix.containers}} + path: | + tests/cypress/screenshots + var/log diff --git a/.github/workflows/unit_tests.yaml b/.github/workflows/unit_tests.yaml index 4bd08ce95..773ec0c7d 100644 --- a/.github/workflows/unit_tests.yaml +++ b/.github/workflows/unit_tests.yaml @@ -1,29 +1,30 @@ name: Unit Tests Checks on: - pull_request: + push: + branches: + - master +# pull_request: jobs: unittests: strategy: matrix: - php-version: [ '7.2', '8.0' ] + php-version: ['8.0' ] fail-fast: false name: PHPUnit runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 with: # test the lowest version, to make sure checks pass on it php-version: ${{ matrix.php-version }} extensions: json, mbstring, pdo, curl, pdo_sqlite coverage: none - - name: Initialise - run: | - sudo composer self-update -q + tools: composer - name: Install dependencies run: | - sudo COMPOSER_MEMORY_LIMIT=-1 COMPOSER_PROCESS_TIMEOUT=60 composer update --prefer-dist --no-progress --no-scripts + COMPOSER_MEMORY_LIMIT=-1 COMPOSER_PROCESS_TIMEOUT=60 composer update --prefer-dist --no-progress --no-scripts - name: run PHP Unit run: ./vendor/bin/phpunit diff --git a/.gitignore b/.gitignore index 83e74fc68..680e99626 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ composer.phar +.phpunit.result.cache ### Built Assets and uploads ### /public/assets/ diff --git a/assets/js/version.js b/assets/js/version.js index f76c1280b..45605e260 100644 --- a/assets/js/version.js +++ b/assets/js/version.js @@ -1,2 +1,2 @@ // generated by genversion -export const version = '5.1.24'; +export const version = '5.1.27'; diff --git a/composer.json b/composer.json index 33b24fad5..8d9c8579e 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ "beberlei/doctrineextensions": "^1.3", "bolt-oss/yaml-migrations": "^1.1.1", "bolt-oss/common": "^3.0.5", - "cocur/slugify": "^4.0", + "cocur/slugify": "^4.5", "composer/composer": "^2.0", "composer/package-versions-deprecated": "^1.11", "doctrine/doctrine-bundle": "^2.4", @@ -133,7 +133,7 @@ "public-dir": "public", "symfony": { "allow-contrib": true, - "require": "^5.2" + "require": "^5.4" } }, "autoload": { diff --git a/config/bundles.php b/config/bundles.php index a7b0da2d3..8194a8122 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -18,7 +18,6 @@ Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'local' => true], - Symfony\Bundle\WebServerBundle\WebServerBundle::class => ['all' => true], Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true], SymfonyCasts\Bundle\ResetPassword\SymfonyCastsResetPasswordBundle::class => ['all' => true], Translation\Bundle\TranslationBundle::class => ['all' => true], diff --git a/package.json b/package.json index 83dab2315..33018a9df 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bolt", - "version": "5.1.24", + "version": "5.1.27", "homepage": "https://boltcms.io", "author": "Bob den Otter (https://boltcms.io)", "license": "MIT", @@ -124,7 +124,7 @@ "a11y:test": "pa11y-ci", "test": "jest", "genversion": "genversion --es6 --semi assets/js/version.js", - "cypress:ci": "cypress run --config-file=tests/cypress/cypress-ci.json --record --parallel --quiet", + "cypress:ci": "cypress run --config-file=tests/cypress/cypress-ci.json --record --parallel --quiet --tag ci", "cypress:dev": "cypress run --config-file=tests/cypress/cypress-dev.json" }, "browserslist": [ diff --git a/php.ini b/php.ini new file mode 100644 index 000000000..ba7503b4b --- /dev/null +++ b/php.ini @@ -0,0 +1,5 @@ +date.timezone=UTC + +session.gc_probability=0 +session.gc_divisor=100000 +session.gc_maxlifetime=1440000 diff --git a/public/theme/skeleton/custom/setcontent_1.twig b/public/theme/skeleton/custom/setcontent_1.twig index 47676e2e3..1d1e89846 100644 --- a/public/theme/skeleton/custom/setcontent_1.twig +++ b/public/theme/skeleton/custom/setcontent_1.twig @@ -211,7 +211,7 @@

Fourteen

{% setcontent pages = 'pages' orderby 'groups.sortorder' printquery %} - + Results: {{ pages|length > 0 ? 'yes' }}
@@ -228,7 +228,7 @@

Fifteen

{% setcontent pages = 'pages' orderby 'groups' printquery %} - + Results: {{ pages|length > 0 ? 'yes' }}
diff --git a/src/Controller/Backend/ContentEditController.php b/src/Controller/Backend/ContentEditController.php index cc7dbfaf5..08ddd675c 100644 --- a/src/Controller/Backend/ContentEditController.php +++ b/src/Controller/Backend/ContentEditController.php @@ -201,17 +201,13 @@ public function save(?Content $originalContent = null, ?ContentValidatorInterfac // check for status (and owner, but that hasn't been implemented in the forms yet) changes if ($originalContent !== null) { - // deny if we detect any of these status fields being changed - if ( - $originalStatus !== $content->getStatus() || - Date::datesDiffer($originalPublishedAt, $content->getPublishedAt()) || - Date::datesDiffer($originalDepublishedAt, $content->getDepublishedAt()) - ) { - $this->denyAccessUnlessGranted(ContentVoter::CONTENT_CHANGE_STATUS, $content); + if ($this->isGranted(ContentVoter::CONTENT_CHANGE_STATUS, $content) === false) { + $content->setStatus($originalStatus); + $content->setPublishedAt($originalPublishedAt); + $content->setDepublishedAt($originalDepublishedAt); } - // deny if owner changes - if ($originalAuthor !== $content->getAuthor()) { - $this->denyAccessUnlessGranted(ContentVoter::CONTENT_CHANGE_OWNERSHIP, $content); + if ($this->isGranted(ContentVoter::CONTENT_CHANGE_OWNERSHIP, $content) === false) { + $content->setAuthor($originalAuthor); } } diff --git a/src/Controller/Backend/GeneralController.php b/src/Controller/Backend/GeneralController.php index 6b3696a38..c7ff8f468 100644 --- a/src/Controller/Backend/GeneralController.php +++ b/src/Controller/Backend/GeneralController.php @@ -37,6 +37,7 @@ public function about(): Response 'os_name' => php_uname('s'), 'os_version' => php_uname('r'), 'memory_limit' => ini_get('memory_limit'), + 'timezone' => ini_get('date.timezone'), ]; return $this->render('@bolt/pages/about.html.twig', $twigVars); diff --git a/src/DataFixtures/ContentFixtures.php b/src/DataFixtures/ContentFixtures.php index bbc46a52d..5b65c9449 100644 --- a/src/DataFixtures/ContentFixtures.php +++ b/src/DataFixtures/ContentFixtures.php @@ -485,7 +485,7 @@ private function getPresetRecords(): array // Only add this fixture if the file exists: It does in the "Git Clone", but not in the // "Composer create-project". - $file = dirname(dirname(__DIR__)) . '/public/theme/skeleton/custom/setcontent_1.twig'; + $file = dirname(__DIR__,2) . '/public/theme/skeleton/custom/setcontent_1.twig'; if (file_exists($file)) { $records['pages'][] = [ 'heading' => 'Setcontent test page', @@ -496,10 +496,10 @@ private function getPresetRecords(): array // Only add this fixture if the file exists: It does in the "Git Clone", but not in the // "Composer create-project". - $file = dirname(dirname(__DIR__)) . '/public/theme/skeleton/custom/setwherecheckbox_1.twig'; + $file = dirname(__DIR__, 2) . '/public/theme/skeleton/custom/setwherecheckbox_1.twig'; if (file_exists($file)) { $records['pages'][] = [ - 'heading' => 'SetContent Where Checkbox test page', + 'heading' => 'SetContent test page Where Checkbox', 'slug' => 'Setwherecheckbox test page', 'template' => 'custom/setwherecheckbox_1.twig', ]; diff --git a/src/DataFixtures/UserFixtures.php b/src/DataFixtures/UserFixtures.php index 2c0a4c544..1f36ad78d 100644 --- a/src/DataFixtures/UserFixtures.php +++ b/src/DataFixtures/UserFixtures.php @@ -100,7 +100,7 @@ private function getUserData(): array [ 'displayname' => 'Crazy Steve', 'username' => 'steve', - 'password' => Str::generatePassword(12), + 'password' => $this->append ? Str::generatePassword(12): '', 'email' => 'henkie@example.org', 'roles' => ['ROLE_EDITOR', 'ROLE_EXTRA_1', 'ROLE_EXTRA_2', 'ROLE_USER_FRONTEND_GROUP1'], 'status' => UserStatus::DISABLED, @@ -108,10 +108,10 @@ private function getUserData(): array [ 'displayname' => 'Jane Doe', 'username' => 'jane_chief', - 'password' => Str::generatePassword(12), + 'password' => $this->append ? Str::generatePassword(12) : 'jane%1', 'email' => 'jane_admin@example.org', 'roles' => ['ROLE_CHIEF_EDITOR'], - 'status' => UserStatus::DISABLED, + 'status' => UserStatus::ENABLED, ], [ 'displayname' => 'Tom Doe', @@ -124,18 +124,18 @@ private function getUserData(): array [ 'displayname' => 'John Doe', 'username' => 'john_editor', - 'password' => Str::generatePassword(12), + 'password' => $this->append ? Str::generatePassword(12): 'john%1', 'email' => 'john_user@example.org', 'roles' => ['ROLE_EDITOR'], - 'status' => UserStatus::DISABLED, + 'status' => UserStatus::ENABLED, ], [ 'displayname' => 'Eddie Enduser', 'username' => 'eddie', - 'password' => Str::generatePassword(12), + 'password' => $this->append ? Str::generatePassword(12): 'eddie%1', 'email' => 'eddie@example.org', 'roles' => ['ROLE_USER'], - 'status' => UserStatus::DISABLED, + 'status' => UserStatus::ENABLED, ], ]; } diff --git a/src/Doctrine/Query/Cast.php b/src/Doctrine/Query/Cast.php index 58c12ab91..68bf4c805 100644 --- a/src/Doctrine/Query/Cast.php +++ b/src/Doctrine/Query/Cast.php @@ -55,7 +55,8 @@ public function parse(Parser $parser): void // doctrine/lexer v2 if (is_array($parser->getLexer()->token)) { $this->second = $parser->getLexer()->token['value']; - } elseif (is_object($parser->getLexer()->token)){ // doctrine/lexer v3 + /** @phpstan-ignore-next-line */ + } elseif (is_object($parser->getLexer()->token)) { // doctrine/lexer v3 $this->second = $parser->getLexer()->token->value; } else { throw new \LogicException('Unable to acccess parser token'); diff --git a/src/Twig/CommonExtension.php b/src/Twig/CommonExtension.php index aee587685..675f6fda9 100644 --- a/src/Twig/CommonExtension.php +++ b/src/Twig/CommonExtension.php @@ -73,9 +73,9 @@ private function getLocale($item): ?string { if (is_string($item)) { $localepattern = '/^[a-z]{2}((-|_)[a-z]{2})?$/m'; - preg_match_all($localepattern, $item, $matches); + $matchCount = preg_match_all($localepattern, $item); - return ! empty($matches) ? $item : null; + return $matchCount > 0 ? $item : null; } elseif ($item instanceof Collection) { return $this->getLocale($item->get('code', null)); } diff --git a/src/Version.php b/src/Version.php index 89d306f21..80be565e7 100644 --- a/src/Version.php +++ b/src/Version.php @@ -23,7 +23,7 @@ final class Version * Stable — 3.0.0 * Development — 3.1.0 alpha 1 */ - public const VERSION = '5.1.24'; + public const VERSION = '5.1.27'; public const CODENAME = ''; /** diff --git a/templates/bundles/ApiPlatformBundle/SwaggerUi/index.html.twig b/templates/bundles/ApiPlatformBundle/SwaggerUi/index.html.twig index 1015f993b..b0a4205b6 100644 --- a/templates/bundles/ApiPlatformBundle/SwaggerUi/index.html.twig +++ b/templates/bundles/ApiPlatformBundle/SwaggerUi/index.html.twig @@ -1,7 +1,7 @@ {% extends '@bolt/_base/layout.html.twig' %} {% block title %} - Bolt API + Bolt OSS API {% endblock %} {% block main %} @@ -22,7 +22,7 @@ {% block stylesheets %} {{ parent() }} - + {# json_encode(65) is for JSON_UNESCAPED_SLASHES|JSON_HEX_TAG to avoid JS XSS #} @@ -31,7 +31,7 @@ {% block javascripts %} {{ parent() }} - - - + + + {% endblock %} diff --git a/templates/bundles/TranslationBundle/WebUI/base.html.twig b/templates/bundles/TranslationBundle/WebUI/base.html.twig index 0c3236930..91bd9fccd 100644 --- a/templates/bundles/TranslationBundle/WebUI/base.html.twig +++ b/templates/bundles/TranslationBundle/WebUI/base.html.twig @@ -44,10 +44,10 @@ var editUrl = "{{ path('translation_edit', {configName: configName, locale:currentLocale,domain:currentDomain}) }}"; {% endif %} - + {% endblock %} {% block stylesheets %} {{ parent() }} - + {% endblock %} diff --git a/templates/pages/about.html.twig b/templates/pages/about.html.twig index 0f0bfef30..772410de4 100644 --- a/templates/pages/about.html.twig +++ b/templates/pages/about.html.twig @@ -14,7 +14,7 @@ {% block main %}

- Bolt {{ constant('Bolt\\Version::VERSION') }} + Bolt OSS {{ constant('Bolt\\Version::VERSION') }} {% if constant('Bolt\\Version::CODENAME') %} - {{ constant('Bolt\\Version::CODENAME') }}{% endif %}

@@ -30,22 +30,27 @@
  • Memory limit: {{ memory_limit }}
  • +
  • Timezone: {{ timezone }} {{ timezone != 'UTC' ? ' Use the UTC timezone in PHP configuration.':'' }}

  • +

    + Bolt OSS is a fork of the original Bolt CMS, which Bob den Otter created. + Following Bob den Otter's passing, the Bolt OSS community and the Code Rhapsody core team maintain Bolt OSS. +

    Bolt is a CMS that strives to be simple, fast, straightforward and enjoyable to use. Both for developers and content-editors. Bolt is Open Source, and as such it uses other Open Source components. If you are a developer you're very welcome to help in the further development of Bolt.

    -

    The ongoing Bolt development takes place under the care of:

    +

    The ongoing Bolt OSS development takes place under the care of:

    Sponsors:

    {# Previous collaborators / sponsors: @@ -65,7 +70,7 @@ {{ 'about.bolt_documentation'|trans }} - + {{ 'about.bolt_on_github'|trans }}

    diff --git a/tests/cypress/cypress-ci.json b/tests/cypress/cypress-ci.json index f95e0a858..38ac3e57b 100644 --- a/tests/cypress/cypress-ci.json +++ b/tests/cypress/cypress-ci.json @@ -5,7 +5,7 @@ "video": false, "supportFile": "tests/cypress/support/index.js", "baseUrl": "http://127.0.0.1:8088", - "projectId": "54gs3j", + "projectId": "eqxvdj", "defaultCommandTimeout": 8000, "retries": 2 } diff --git a/tests/cypress/cypress-dev.json b/tests/cypress/cypress-dev.json index 6e8b09771..f1fa6c340 100644 --- a/tests/cypress/cypress-dev.json +++ b/tests/cypress/cypress-dev.json @@ -4,7 +4,7 @@ "screenshotsFolder": "tests/cypress/screenshots", "videosFolder": "tests/cypress/videos", "supportFile": "tests/cypress/support/index.js", - "baseUrl": "https://127.0.0.1:8001", + "baseUrl": "http://127.0.0.1:8001", "viewportWidth": 1920, "viewportHeight": 1080, "retries": 2 diff --git a/tests/cypress/integration/api_getcontent.spec.js b/tests/cypress/integration/api_getcontent.spec.js index 5dd0b4ae6..f1aa877ec 100644 --- a/tests/cypress/integration/api_getcontent.spec.js +++ b/tests/cypress/integration/api_getcontent.spec.js @@ -6,19 +6,20 @@ describe('As a user I want to fetch all contents of an API' , () => { cy.visit('/bolt/api'); cy.get('#operations-Content-getContentCollection').eq(0).click(); cy.get('.response-col_status').should('contain', '200'); - }) + }); it('Checks if the contents.json is filled with all content', () => { + // tag: ci cy.login(); - cy.request({ - url: '/api/contents.json', + cy.request({ + url: '/api/contents.json', failOnStatusCode: false, auth: { username: 'admin', password: 'admin%1', }, }).then((response) => { - return new Promise(resolve => { + return new Promise(resolve => { expect(response).property('status').to.eq(200) expect(response.body[0]).property('id').to.not.be.oneOf([null, ""]) const respBody = response.body[0]; @@ -29,16 +30,17 @@ describe('As a user I want to fetch all contents of an API' , () => { }) it('Check if it returns JSON of a single record', () => { + // tag: ci cy.login(); - cy.request({ - url: '/api/contents/1.json', + cy.request({ + url: '/api/contents/1.json', failOnStatusCode: false, auth: { username: 'admin', password: 'admin%1', }, }).then((response) => { - return new Promise(resolve => { + return new Promise(resolve => { expect(response).property('status').to.eq(200) expect(response.body).property('id').to.not.be.oneOf([null, ""]) const respBody = response.body[0]; @@ -47,18 +49,19 @@ describe('As a user I want to fetch all contents of an API' , () => { }); }) }) - + it('Check if the JSON LD format is working', () => { + // tag: ci cy.login(); - cy.request({ - url: '/api/contents.jsonld', + cy.request({ + url: '/api/contents.jsonld', failOnStatusCode: false, auth: { username: 'admin', password: 'admin%1', }, }).then((response) => { - return new Promise(resolve => { + return new Promise(resolve => { expect(response).property('status').to.eq(200) expect(response.body).property('hydra:totalItems').to.not.be.oneOf([null, "", 0]) const respBody = response.body; @@ -69,16 +72,17 @@ describe('As a user I want to fetch all contents of an API' , () => { }) //TODO fix this test once we can navigate inside object it('Check if the JSON LD format is working for single contenttypes like homepage', () => { + // tag: ci cy.login(); - cy.request({ - url: '/api/contents.jsonld?contentType=homepage', + cy.request({ + url: '/api/contents.jsonld?contentType=homepage', failOnStatusCode: false, auth: { username: 'admin', password: 'admin%1', }, }).then((response) => { - return new Promise(resolve => { + return new Promise(resolve => { expect(response).property('status').to.eq(200) expect(response.body).property('hydra:totalItems').to.not.be.oneOf([null, "", 0]) const respBody = response.body; @@ -89,16 +93,17 @@ describe('As a user I want to fetch all contents of an API' , () => { }) it('Check if the JSON LD format is working for single records', () => { + // tag: ci cy.login(); - cy.request({ - url: '/api/contents/1.jsonld', + cy.request({ + url: '/api/contents/1.jsonld', failOnStatusCode: false, auth: { username: 'admin', password: 'admin%1', }, }).then((response) => { - return new Promise(resolve => { + return new Promise(resolve => { expect(response).property('status').to.eq(200) expect(response.body).property('id').to.not.be.oneOf([null, ""]) const respBody = response.body; @@ -109,17 +114,18 @@ describe('As a user I want to fetch all contents of an API' , () => { }) }) -describe('Test reading JSON Fields', () => { +describe('Test reading JSON Fields', () => { it('should read the values of the returned data in JSON', () => { + // tag: ci cy.request({ - url:`/api/contents/1/fields.json`, + url:`/api/contents/1/fields.json`, failOnStatusCode: false, auth: { username: 'admin', password: 'admin%1', }, }).then((response) => { - return new Promise(resolve => { + return new Promise(resolve => { expect(response).property('status').to.eq(200) expect(response.body[0]).property('name').to.not.be.oneOf([null, ""]) const respBody = response.body[0]; @@ -130,15 +136,16 @@ describe('Test reading JSON Fields', () => { }) it('should read the values of the returned data in JSON ld', () => { + // tag: ci cy.request({ - url:`/api/contents/1/fields.jsonld`, + url:`/api/contents/1/fields.jsonld`, failOnStatusCode: false, auth: { username: 'admin', password: 'admin%1', }, }).then((response) => { - return new Promise(resolve => { + return new Promise(resolve => { expect(response).property('status').to.eq(200) expect(response.body).property('hydra:totalItems').to.not.be.oneOf([null, "", 0]) const respBody = response.body; diff --git a/tests/cypress/integration/backend_api.spec.js b/tests/cypress/integration/backend_api.spec.js index c23777b9e..e7c480843 100644 --- a/tests/cypress/integration/backend_api.spec.js +++ b/tests/cypress/integration/backend_api.spec.js @@ -2,8 +2,9 @@ describe('As an admin, I want to see the API documentation page', () => { it('checks that the API page exists', () => { + // tag: ci cy.login(); cy.visit('/bolt/api'); - cy.get('.admin__header--title').should('contain', 'Bolt API'); + cy.get('.admin__header--title').should('contain', 'Bolt OSS API'); }) }); diff --git a/tests/cypress/integration/backend_translations.spec.js b/tests/cypress/integration/backend_translations.spec.js index d0761c236..bf107f70f 100644 --- a/tests/cypress/integration/backend_translations.spec.js +++ b/tests/cypress/integration/backend_translations.spec.js @@ -2,6 +2,7 @@ describe('As an admin I want to see Translations page', () => { it('checks that the translations page exists', () => { + // tag: ci cy.login(); cy.visit('/bolt/_trans'); cy.get('.admin__header--title').should('contain', 'Edit Translations'); diff --git a/tests/cypress/integration/bulk_actions.spec.js b/tests/cypress/integration/bulk_actions.spec.js index e43a287a0..00ab8918e 100644 --- a/tests/cypress/integration/bulk_actions.spec.js +++ b/tests/cypress/integration/bulk_actions.spec.js @@ -2,6 +2,7 @@ describe('As an admin I should be able to run bulk actions', () => { it('checks if an admin can see all items', () => { + // tag: ci cy.login(); cy.visit('/bolt/content/pages'); cy.get("label[for='selectAll']").should('exist'); @@ -14,6 +15,7 @@ describe('As an admin I should be able to run bulk actions', () => { }) it('checks if an admin can make multiple changes at once', () => { + // tag: ci cy.login(); cy.visit('/bolt/content/tests'); cy.get(".listing__filter .custom-checkbox").click(); diff --git a/tests/cypress/integration/chief_editor_permissions.spec.js b/tests/cypress/integration/chief_editor_permissions.spec.js index 83fb40353..e06dc08df 100644 --- a/tests/cypress/integration/chief_editor_permissions.spec.js +++ b/tests/cypress/integration/chief_editor_permissions.spec.js @@ -2,6 +2,7 @@ describe('Check permissions of a chief_editor', () => { it('checks all permissions of a chief editor', () => { + // tag: ci cy.login('jane_chief', 'jane%1'); // TODO Wait for cache fix diff --git a/tests/cypress/integration/contenttype_permissions.spec.js b/tests/cypress/integration/contenttype_permissions.spec.js index c2e894d61..09843c18e 100644 --- a/tests/cypress/integration/contenttype_permissions.spec.js +++ b/tests/cypress/integration/contenttype_permissions.spec.js @@ -2,6 +2,7 @@ describe('Edit content as chief editor and editor without being the owner', () => { it('checks that the chief editor and editor can edit someone else\'s content', () => { + // tag: ci cy.login('jane_chief', 'jane%1'); cy.visit('/bolt/content/pages'); @@ -40,6 +41,7 @@ describe('Edit content as chief editor and editor without being the owner', () = describe('Create content as editor and delete it as chief editor', () => { it('checks that editors can create content and chief editors can delete it', () => { + // tag: ci cy.login('john_editor', 'john%1'); cy.visit('/bolt/content/pages'); @@ -70,6 +72,7 @@ describe('Create content as editor and delete it as chief editor', () => { describe('Change content post status as chief editor', () => { it('checks that the chief editor can change a post\'s status', () => { + // tag: ci cy.login('jane_chief', 'jane%1'); cy.visit('/bolt/content/pages'); diff --git a/tests/cypress/integration/create_delete_user.spec.js b/tests/cypress/integration/create_delete_user.spec.js index ebdf6b12d..72717fb79 100644 --- a/tests/cypress/integration/create_delete_user.spec.js +++ b/tests/cypress/integration/create_delete_user.spec.js @@ -2,6 +2,7 @@ describe('Create/delete user', () => { it('checks that an admin can create and delete users', () => { + // tag: ci cy.login(); //CACHE CLEAR diff --git a/tests/cypress/integration/dashboard_globalsearch.spec.js b/tests/cypress/integration/dashboard_globalsearch.spec.js index 4b1f3cd74..a0454f7a4 100644 --- a/tests/cypress/integration/dashboard_globalsearch.spec.js +++ b/tests/cypress/integration/dashboard_globalsearch.spec.js @@ -2,6 +2,7 @@ describe('As an Admin I want to filter content', () => { it('checks that content filtering works as an admin', () => { + // tag: ci cy.login(); cy.visit('/bolt'); @@ -10,7 +11,7 @@ describe('As an Admin I want to filter content', () => { cy.get('#global-search').type('a'); cy.get('button[title="Search"]').click(); - cy.url().should('contain', '/bolt/?filter=a'); + cy.url().should('contain', '/bolt/?filter=a'); cy.get('.listing--container').its('length').should('eq', 8); cy.get('h1').should('contain', "All content, filtered by 'a'"); @@ -19,7 +20,7 @@ describe('As an Admin I want to filter content', () => { cy.get('#global-search').clear(); cy.get('#global-search').type('Entries'); cy.get('button[title="Search"]').click(); - cy.url().should('contain', '/bolt/?filter=Entries'); + cy.url().should('contain', '/bolt/?filter=Entries'); cy.get('.listing--container').its('length').should('eq', 1); cy.get('.listing--container').should('contain', "Entries"); @@ -28,7 +29,7 @@ describe('As an Admin I want to filter content', () => { cy.get('#global-search').clear(); cy.get('#global-search').type(' '); cy.get('button[title="Search"]').click(); - cy.url().should('contain', '/bolt'); + cy.url().should('contain', '/bolt'); cy.get('.listing--container').its('length').should('eq', 8); }) }); diff --git a/tests/cypress/integration/disable_enable_user.spec.js b/tests/cypress/integration/disable_enable_user.spec.js index 4c913a908..a0302d2da 100644 --- a/tests/cypress/integration/disable_enable_user.spec.js +++ b/tests/cypress/integration/disable_enable_user.spec.js @@ -2,6 +2,7 @@ describe('Disable/enable users', () => { it('checks that an admin can disable/enable another user', () => { + // tag: ci cy.visit('/bolt/login'); cy.get('input[name="login[username]"]').type('jane_chief'); cy.get('input[name="login[password]"]').type('jane%1' + '{enter}'); diff --git a/tests/cypress/integration/display_listings.spec.js b/tests/cypress/integration/display_listings.spec.js index 370db7b64..d2768d6f6 100644 --- a/tests/cypress/integration/display_listings.spec.js +++ b/tests/cypress/integration/display_listings.spec.js @@ -2,10 +2,11 @@ describe('As an admin I want to see Dashboard page', () => { it('checks that the dashboard listings work', () => { + // tag: ci cy.login(); cy.get('.admin__header--title').should('contain', 'Dashboard'); cy.get('.listing__row').should('exist'); cy.get('.listing__row').its('length').should('eq', 8) }) -}); \ No newline at end of file +}); diff --git a/tests/cypress/integration/display_record.spec.js b/tests/cypress/integration/display_record.spec.js index 23c42592a..d14ccddd7 100644 --- a/tests/cypress/integration/display_record.spec.js +++ b/tests/cypress/integration/display_record.spec.js @@ -2,12 +2,14 @@ describe('As a user I want to display a single record', () => { it('checks if a record exists', () => { + // tag: ci cy.visit('/entry/this-is-a-record-in-the-entries-contenttype'); cy.get('.title').should('have.length', 1); cy.get('.edit-link').should('not.exist'); }); it('checks if an admin can edit a record', () => { + // tag: ci cy.login(); cy.visit('/entry/this-is-a-record-in-the-entries-contenttype'); cy.get('.title').should('have.length', 1); @@ -15,12 +17,14 @@ describe('As a user I want to display a single record', () => { }); it('checks if you can see the difference between records with a Title and a Heading', () => { + // tag: ci cy.visit('/page/2'); cy.get('.heading').should('have.length', 1); cy.get('.title').should('not.exist'); }); it('checks for correct canonical URL', () => { + // tag: ci cy.visit('/page/this-is-a-page'); cy.get("link[rel='canonical']").should('have.attr', 'href', Cypress.config().baseUrl + '/page/this-is-a-page'); diff --git a/tests/cypress/integration/display_record_test.spec.js b/tests/cypress/integration/display_record_test.spec.js index 6da381237..093d9e207 100644 --- a/tests/cypress/integration/display_record_test.spec.js +++ b/tests/cypress/integration/display_record_test.spec.js @@ -2,12 +2,14 @@ describe('As a user I want to see how the record is displayed', () => { it('checks that the record title is displayed as a user', () => { + // tag: ci cy.visit('/test/title-of-the-test'); cy.get('.title').should('have.length', 1); cy.get('.title').should('contain', '74: Title of the test'); }) it('checks that fields are escaped as a user', () => { + // tag: ci cy.visit('/test/title-of-the-test'); cy.get('.title').should('have.length', 1); @@ -28,6 +30,7 @@ describe('As a user I want to see how the record is displayed', () => { }) it('checks that file fields are displayed as a user', () => { + // tag: ci cy.visit('/test/title-of-the-test'); cy.get('.title').should('have.length', 1); cy.get('#attachment #filename').should('contain', 'joey.jpg'); diff --git a/tests/cypress/integration/display_search.spec.js b/tests/cypress/integration/display_search.spec.js index c6995fecc..a7e32509c 100644 --- a/tests/cypress/integration/display_search.spec.js +++ b/tests/cypress/integration/display_search.spec.js @@ -2,7 +2,8 @@ describe('As a user I want to display search results', () => { it('checks that search results are displayed as a user', () => { - + // tag: ci + cy.visit('/'); cy.get('input[type="search"]').type('consequatur'); cy.get('button[type="submit"]').click(); @@ -21,7 +22,7 @@ describe('As a user I want to display search results', () => { cy.get('article').should('not.exist'); cy.get('input[name="searchTerm"]').eq(0).clear(); - cy.get('input[name="searchTerm"]').eq(0).type(' '); + cy.get('input[name="searchTerm"]').eq(0).type(' '); cy.get('button[type="submit"]').eq(0).click(); cy.url().should('include', '/search'); diff --git a/tests/cypress/integration/display_taxonomies.spec.js b/tests/cypress/integration/display_taxonomies.spec.js index f8d06d76f..1ed617070 100644 --- a/tests/cypress/integration/display_taxonomies.spec.js +++ b/tests/cypress/integration/display_taxonomies.spec.js @@ -2,6 +2,7 @@ describe('As a user I want to see taxonomies in records and listings', () => { it('checks if there are taxonomies on a record', () => { + // tag: ci cy.visit('/entry/this-is-a-record-in-the-entries-contenttype'); cy.get('.title').should('have.length', 1); cy.get('.taxonomy-categories').its('length').should('eq', 2); @@ -9,6 +10,7 @@ describe('As a user I want to see taxonomies in records and listings', () => { }); it('checks if there is a listing of a taxonomy', () => { + // tag: ci cy.login(); cy.visit('/entry/this-is-a-record-in-the-entries-contenttype'); cy.get('.title').should('have.length', 1); diff --git a/tests/cypress/integration/edit_record_1_change_title.spec.js b/tests/cypress/integration/edit_record_1_change_title.spec.js index 5c86c7325..80a35cec6 100644 --- a/tests/cypress/integration/edit_record_1_change_title.spec.js +++ b/tests/cypress/integration/edit_record_1_change_title.spec.js @@ -2,6 +2,7 @@ describe('As an Admin I want to change the title and the locale of a record', () => { it("checks if an admin can change a record's title", () => { + // tag: ci cy.login(); cy.visit('/bolt/edit/30'); cy.get('input[id="field-title"]').clear(); @@ -17,6 +18,7 @@ describe('As an Admin I want to change the title and the locale of a record', () }) it("checks if an admin can change a record's title in another language", () => { + // tag: ci cy.login(); cy.visit('/bolt/edit/1'); cy.get('input[id="field-title"]').clear(); diff --git a/tests/cypress/integration/edit_record_1_content.spec.js b/tests/cypress/integration/edit_record_1_content.spec.js index 894566689..a7d5106b4 100644 --- a/tests/cypress/integration/edit_record_1_content.spec.js +++ b/tests/cypress/integration/edit_record_1_content.spec.js @@ -2,18 +2,21 @@ describe('As an Admin I want to see separators, placeholders and default values', () => { it('checks if an admin can see separated content (separator)', () => { + // tag: ci cy.login(); cy.visit('/bolt/edit/43'); cy.get('#field--field-html').find('hr').its('length').should('eq', 1); }) it('checks if an admin can see placeholder on new content', () => { + // tag: ci cy.login(); cy.visit('/bolt/new/showcases'); cy.get('input[name="fields[title]"]').should('have.attr', 'placeholder').and('match', /Placeholder for the title/); }) it('checks if an admin can see default values', () => { + // tag: ci cy.login(); cy.visit('/bolt'); @@ -35,8 +38,8 @@ describe('As an Admin I want to see separators, placeholders and default values' cy.get('input[name="collections[collection_field][photo][3][filename]"]').should('have.value', 'joey.jpg'); cy.get('input[name="collections[collection_field][photo][3][alt]"]').should('have.value', 'Photo of a foal'); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).scrollIntoView(); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).click(); + cy.get('button[class="btn btn-success mb-0"]').eq(1).scrollIntoView(); + cy.get('button[class="btn btn-success mb-0"]').eq(1).click(); cy.get('input[name="fields[title]"]').should('have.value', 'Title of a test contenttype'); cy.get('input[name="fields[image][filename]"]').should('have.value', 'foal.jpg'); @@ -56,6 +59,7 @@ describe('As an Admin I want to see separators, placeholders and default values' describe('As an Admin, I want to duplicate a page', () => { it('checks if an admin can duplicate a page', () => { + // tag: ci cy.login(); cy.visit('/bolt/content/pages'); @@ -66,8 +70,8 @@ describe('As an Admin, I want to duplicate a page', () => { cy.get('input[name="fields[heading]"]').should('have.value', 'This is a page'); cy.get('input[name="fields[slug]"]').should('have.value', 'this-is-a-page'); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).scrollIntoView(); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).click(); + cy.get('button[class="btn btn-success mb-0"]').eq(1).scrollIntoView(); + cy.get('button[class="btn btn-success mb-0"]').eq(1).click(); cy.get('input[name="fields[heading]"]').should('have.value', 'This is a page'); cy.get('input[name="fields[slug]"]').should('have.value', 'this-is-a-page-1'); diff --git a/tests/cypress/integration/edit_record_1_field.spec.js b/tests/cypress/integration/edit_record_1_field.spec.js index f53a5c8c9..e67737396 100644 --- a/tests/cypress/integration/edit_record_1_field.spec.js +++ b/tests/cypress/integration/edit_record_1_field.spec.js @@ -2,6 +2,7 @@ describe('As an Admin I want to be able to make use of the embed, infobox and image fields', () => { it('checks if an admin can use the embed field', () => { + // tag: ci cy.login(); cy.visit('/bolt/edit/44'); cy.get('a[id="media-tab"]').click(); @@ -24,6 +25,7 @@ describe('As an Admin I want to be able to make use of the embed, infobox and im }) it('checks if an admin can see the infobox field', () => { + // tag: ci cy.login(); cy.visit('/bolt/edit/38'); @@ -37,6 +39,7 @@ describe('As an Admin I want to be able to make use of the embed, infobox and im }) it('checks if an admin can reset an image field', () => { + // tag: ci cy.login(); cy.visit('/bolt/edit/40'); cy.get('a[id="media-tab"]').click(); @@ -76,7 +79,7 @@ describe('As an Admin I want to be able to make use of the date & datetime field cy.visit('/bolt/profile-edit'); cy.get('#multiselect-user_locale > div > div.multiselect__select').scrollIntoView(); cy.get('#multiselect-user_locale > div > div.multiselect__select').click(); - cy.contains('English (English, en)').click(); + cy.contains('anglais (English, en)').click(); cy.get('#edituser > button').scrollIntoView(); cy.get('form[id="edituser"]').submit(); @@ -85,6 +88,7 @@ describe('As an Admin I want to be able to make use of the date & datetime field }) it('checks if an admin can use the date field', () => { + // tag: ci cy.login(); cy.visit('/bolt/edit/44'); cy.get('a[id="other-tab"]').click(); @@ -100,6 +104,7 @@ describe('As an Admin I want to be able to make use of the date & datetime field }) it('checks if an admin can use the datetime field with an AM time (with AM/PM selector)', () => { + // tag: ci cy.login(); cy.visit('/bolt/edit/44'); cy.get('a[id="other-tab"]').click(); diff --git a/tests/cypress/integration/edit_record_1_fill_list.spec.js b/tests/cypress/integration/edit_record_1_fill_list.spec.js index d6aa87017..b2fd7354e 100644 --- a/tests/cypress/integration/edit_record_1_fill_list.spec.js +++ b/tests/cypress/integration/edit_record_1_fill_list.spec.js @@ -2,6 +2,7 @@ describe('As an Admin I want to fill in an imagelist and filelist', () => { it('checks if an admin can fill in an imagelist', () => { + // tag: ci cy.login(); cy.visit('/bolt/edit/42'); cy.get('a[id="media-tab"]').click(); @@ -50,13 +51,14 @@ describe('As an Admin I want to fill in an imagelist and filelist', () => { cy.get('div[class="btn-group mr-2"]').eq(11).find('button[disabled="disabled"]'); cy.get('.form-fieldsgroup:nth-child(1) > .editor__image .btn:nth-child(3)').click(); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).click(); + cy.get('button[class="btn btn-success mb-0"]').eq(1).click(); //TODO: move checking for elements before saving changes(for some reason it doesn't work) cy.get('.editor__imagelist').find('div[class="form-fieldsgroup"]').its('length').should('eq', 4); cy.url().should('contain', '/bolt/edit/42?edit_locale=en#media'); }) it('checks if an admin can fill in an filelist', () => { + // tag: ci cy.login(); cy.visit('/bolt/edit/42'); cy.get('a[id="files-tab"]').click(); @@ -100,7 +102,7 @@ describe('As an Admin I want to fill in an imagelist and filelist', () => { cy.get('.form-fieldsgroup:nth-child(1) > .editor__file .btn-hidden-danger').click(); cy.get('button[class="btn btn-tertiary"]').eq(0).should('be.enabled'); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).click(); + cy.get('button[class="btn btn-success mb-0"]').eq(1).click(); //TODO: move checking for elements before saving changes(for some reason it doesn't work) cy.get('.editor-filelist').find('div[class="form-fieldsgroup"]').its('length').should('eq', 4); cy.url().should('contain', '/bolt/edit/42?edit_locale=en#files'); diff --git a/tests/cypress/integration/edit_record_1_fill_set_collection.spec.js b/tests/cypress/integration/edit_record_1_fill_set_collection.spec.js index 62e511598..edb4b995b 100644 --- a/tests/cypress/integration/edit_record_1_fill_set_collection.spec.js +++ b/tests/cypress/integration/edit_record_1_fill_set_collection.spec.js @@ -2,6 +2,7 @@ describe('As an Admin I want to fill in a Set and an Collection', () => { it('checks if an admin can fill in a set', () => { + // tag: ci cy.login(); cy.visit('/bolt/edit/43'); cy.get('.editor__tabbar').should('contain', 'Sets'); @@ -19,8 +20,8 @@ describe('As an Admin I want to fill in a Set and an Collection', () => { cy.get('textarea[name="sets[set][textarea]"]').clear(); cy.get('textarea[name="sets[set][textarea]"]').type('Bar'); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).scrollIntoView(); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).click(); + cy.get('button[class="btn btn-success mb-0"]').eq(1).scrollIntoView(); + cy.get('button[class="btn btn-success mb-0"]').eq(1).click(); cy.url().should('contain', '/bolt/edit/43?edit_locale=en#sets'); cy.get('input[name="sets[set][title]"]').should('have.value', 'Foo'); @@ -29,6 +30,7 @@ describe('As an Admin I want to fill in a Set and an Collection', () => { }) it('checks if an admin can fill in a collection', () => { + // tag: ci cy.login(); cy.visit('/bolt/edit/43'); cy.get('.editor__tabbar').should('contain', 'Collections'); @@ -58,8 +60,8 @@ describe('As an Admin I want to fill in a Set and an Collection', () => { cy.get('.collection-item:nth-child(4) .action-move-down-collection-item').click(); cy.get('div[data-label="Set inside Collection"]').should('exist'); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).scrollIntoView(); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).click(); + cy.get('button[class="btn btn-success mb-0"]').eq(1).scrollIntoView(); + cy.get('button[class="btn btn-success mb-0"]').eq(1).click(); cy.url().should('contain', '/bolt/edit/43?edit_locale=en#collections'); cy.get(".collection-item:nth-child(4) input[type='text']").should('have.value', 'Hey, Bolt'); @@ -88,8 +90,8 @@ describe('As an Admin I want to fill in a Set and an Collection', () => { cy.wait(1000); cy.get('.collection-item').its('length').should('eq', 2); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).scrollIntoView(); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).click({force: true}); + cy.get('button[class="btn btn-success mb-0"]').eq(1).scrollIntoView(); + cy.get('button[class="btn btn-success mb-0"]').eq(1).click({force: true}); cy.get('.collection-item').its('length').should('eq', 2); cy.get('.collection-item-title').should('not.contain', 'Hey, Bolt'); diff --git a/tests/cypress/integration/edit_record_2.spec.js b/tests/cypress/integration/edit_record_2.spec.js index e0b0984c9..c7a5478b1 100644 --- a/tests/cypress/integration/edit_record_2.spec.js +++ b/tests/cypress/integration/edit_record_2.spec.js @@ -2,18 +2,19 @@ describe('As an Admin I want to view saved changes of a record or preview these', () => { it('checks if an admin can view saved changes on a record', () => { + // tag: ci cy.login(); cy.visit('/bolt/edit/2'); cy.get('input[id="field-heading"]').clear(); cy.get('input[id="field-heading"]').type('This is the title in the wrong locale'); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).scrollIntoView(); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).click(); + cy.get('button[class="btn btn-success mb-0"]').eq(1).scrollIntoView(); + cy.get('button[class="btn btn-success mb-0"]').eq(1).click(); cy.visit('/bolt/edit/2?edit_locale=nl'); cy.get('input[id="field-heading"]').clear(); cy.get('input[id="field-heading"]').type('This is the title in the right locale'); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).scrollIntoView(); - cy.get('button[class="btn btn-success mb-0 "]').eq(1).click(); + cy.get('button[class="btn btn-success mb-0"]').eq(1).scrollIntoView(); + cy.get('button[class="btn btn-success mb-0"]').eq(1).click(); cy.url().should('contain', '/bolt/edit/2?edit_locale=nl'); cy.get('a[class="btn btn-tertiary btn-sm"]').scrollIntoView(); @@ -25,11 +26,12 @@ describe('As an Admin I want to view saved changes of a record or preview these' }) it('checks if an admin can preview an edited record', () => { + // tag: ci cy.login(); cy.visit('/bolt/edit/30'); cy.get('input[id="field-title"]').clear(); cy.get('input[id="field-title"]').type('Check preview'); - + cy.get('#button-preview').invoke('removeAttr', 'formtarget').click({force: true}); cy.url().should('contain', '/preview/30'); cy.get('body').should('contain', 'Check preview'); diff --git a/tests/cypress/integration/edit_users.spec.js b/tests/cypress/integration/edit_users.spec.js index 96b622394..945a65d0b 100644 --- a/tests/cypress/integration/edit_users.spec.js +++ b/tests/cypress/integration/edit_users.spec.js @@ -2,6 +2,7 @@ describe('Edit user successfully, Edit users incorrectly', () => { it('checks that an admin can edit users', () => { + // tag: ci cy.login(); cy.visit('/bolt/users'); @@ -25,6 +26,7 @@ describe('Edit user successfully, Edit users incorrectly', () => { }) it('checks that a user can change their display name', () => { + // tag: ci cy.visit('/bolt/login'); cy.get('input[name="login[username]"]').type('jane_chief'); cy.get('input[name="login[password]"]').type('jane%1' + '{enter}'); @@ -43,6 +45,7 @@ describe('Edit user successfully, Edit users incorrectly', () => { }) it('checks that an admin can\'t edit a user with incorrect details', () => { + // tag: ci cy.login(); cy.visit('/bolt/user-edit/2'); @@ -63,6 +66,7 @@ describe('Edit user successfully, Edit users incorrectly', () => { }) it('checks that a user can\'t edit their profile with an incorrect display name', () => { + // tag: ci cy.visit('/bolt/login'); cy.get('input[name="login[username]"]').type('jane_chief'); cy.get('input[name="login[password]"]').type('jane%1' + '{enter}'); diff --git a/tests/cypress/integration/editor_permissions.spec.js b/tests/cypress/integration/editor_permissions.spec.js index 9e15e9f92..e9d605cad 100644 --- a/tests/cypress/integration/editor_permissions.spec.js +++ b/tests/cypress/integration/editor_permissions.spec.js @@ -2,12 +2,14 @@ describe('Check all editors privileges', () => { it('checks if an editor can access Configuration', () => { + // tag: ci cy.login('john_editor', 'john%1'); cy.url().should('contain', '/bolt/'); cy.get('ul[class="admin__sidebar--menu"]').find('li').find('a[href="/bolt/menu/configuration"]').should('not.exist'); }) it('checks if an editor can access maintenance pages besides About Bolt', () => { + // tag: ci cy.login('john_editor', 'john%1'); cy.url().should('contain', '/bolt/'); cy.get('ul[class="admin__sidebar--menu"]').find('li').eq(10).trigger('mouseover'); @@ -42,6 +44,7 @@ describe('Check all editors privileges', () => { }) it('checks if an editor can access files', () => { + // tag: ci cy.visit('/bolt/login'); cy.login('john_editor', 'john%1'); cy.url().should('contain', '/bolt/'); diff --git a/tests/cypress/integration/extension_routing.spec.js b/tests/cypress/integration/extension_routing.spec.js index 3b6ea45e6..d469cff32 100644 --- a/tests/cypress/integration/extension_routing.spec.js +++ b/tests/cypress/integration/extension_routing.spec.js @@ -2,6 +2,7 @@ describe('I want to see a page, added by an Extension', () => { it('checks that extension pages exist', () => { + // tag: ci cy.visit('/extensions/reference/Zebedeus'); cy.get('p').should('contain', 'Hello, Zebedeus'); diff --git a/tests/cypress/integration/filemanager.spec.js b/tests/cypress/integration/filemanager.spec.js index 95e9efd3d..4ab04ea27 100644 --- a/tests/cypress/integration/filemanager.spec.js +++ b/tests/cypress/integration/filemanager.spec.js @@ -12,6 +12,7 @@ describe('As an Admin I am able to use the files section', () => { }) it('checks if an admin can delete files in the Files section', () => { + // tag: ci cy.login(); cy.visit('/bolt/filemanager/files'); cy.get('#files-list tr td b').eq(1).contains('_b-penguin.jpeg'); @@ -28,6 +29,7 @@ describe('As an Admin I am able to use the files section', () => { }) it('checks if an admin can cancel deleting files in the Files section', () => { + // tag: ci cy.login(); cy.visit('/bolt/filemanager/files'); cy.get('#files-list tr td b').eq(0).contains('_a-sunrise.jpeg'); @@ -44,6 +46,7 @@ describe('As an Admin I am able to use the files section', () => { }) it('checks if an admin can duplicate files in the Files section', () => { + // tag: ci cy.login(); cy.visit('/bolt/filemanager/files'); cy.get('#files-list tr td b').eq(0).contains('_a-sunrise.jpeg'); @@ -77,6 +80,7 @@ describe('As an Admin I am able to use the files section', () => { }) it('checks if an admin can create and delete folders in the Files section', () => { + // tag: ci cy.login(); cy.visit('/bolt/filemanager/files'); cy.get('a').should('not.contain', 'a-new-folder/'); diff --git a/tests/cypress/integration/frontend_menu.spec.js b/tests/cypress/integration/frontend_menu.spec.js index 53b19f2a7..8ec99dbbe 100644 --- a/tests/cypress/integration/frontend_menu.spec.js +++ b/tests/cypress/integration/frontend_menu.spec.js @@ -2,6 +2,7 @@ describe('As a user I want to see the menu\'s in the frontend', () => { it('checks if the frontend menu exists', () => { + // tag: ci cy.visit(Cypress.config().baseUrl); cy.get('.menu .first').should('contain', 'Home'); cy.get('.menu .bolt-site').should('contain', 'The Bolt site'); @@ -9,6 +10,7 @@ describe('As a user I want to see the menu\'s in the frontend', () => { }) it('checks if the multi-level frontend menu exists', () => { + // tag: ci cy.visit('/test/title-of-the-test'); cy.get('.menu .item-1').should('contain', 'Item 1'); cy.get('.menu .item-1-1').should('contain', 'Item 1.1'); diff --git a/tests/cypress/integration/homepage.spec.js b/tests/cypress/integration/homepage.spec.js index 75876857b..bd5cf4011 100644 --- a/tests/cypress/integration/homepage.spec.js +++ b/tests/cypress/integration/homepage.spec.js @@ -2,8 +2,9 @@ describe('I want to display Homepage', () => { it('checks that the homepage exists', () => { + // tag: ci cy.visit('/'); cy.get('h2').should('contain', 'Bolt Core Git Clone'); cy.get('h5').should('contain', 'Recent Pages'); }) -}); \ No newline at end of file +}); diff --git a/tests/cypress/integration/kitchensink.spec.js b/tests/cypress/integration/kitchensink.spec.js index d8746ee91..ee746675c 100644 --- a/tests/cypress/integration/kitchensink.spec.js +++ b/tests/cypress/integration/kitchensink.spec.js @@ -2,6 +2,7 @@ describe('As an admin I want to see the Kitchensink page', () => { it('checks that the Kitchensink page exists and works', () => { + // tag: ci cy.login(); cy.visit('/bolt/kitchensink'); cy.get('.admin__header--title').should('contain', 'Kitchensink'); diff --git a/tests/cypress/integration/login.spec.js b/tests/cypress/integration/login.spec.js index 2981325bf..91a68c814 100644 --- a/tests/cypress/integration/login.spec.js +++ b/tests/cypress/integration/login.spec.js @@ -2,7 +2,8 @@ describe('As an admin I attempt to log in to Dashboard with incorrect credentials', () => { it("checks that logging in with incorrect credentials doesn't work", () => { - + // tag: ci + cy.visit('/bolt/login'); cy.get('input[name="login[username]"]').type('admin'); diff --git a/tests/cypress/integration/record_listing.spec.js b/tests/cypress/integration/record_listing.spec.js index 1530eca39..9f67f3b63 100644 --- a/tests/cypress/integration/record_listing.spec.js +++ b/tests/cypress/integration/record_listing.spec.js @@ -2,6 +2,7 @@ describe('As an Admin I want to use record listing', () => { it('checks that an admin can navigate over the record listing', () => { + // tag: ci cy.login(); cy.get('a[rel=next]').scrollIntoView(); cy.get('a[rel=next]').click(); @@ -9,6 +10,7 @@ describe('As an Admin I want to use record listing', () => { }) it('checks that an admin can sort content', () => { + // tag: ci cy.login(); cy.visit('/bolt'); @@ -18,7 +20,7 @@ describe('As an Admin I want to use record listing', () => { cy.get('div[class="card-header"]').should('contain', 'Contentlisting'); cy.get('select[name="sortBy"]').select('author'); - cy.get('button[class="btn btn-secondary mb-0 "]').should('contain', 'Filter').click(); + cy.get('button[class="btn btn-secondary mb-0"]').should('contain', 'Filter').click(); cy.url().should('contain', '/bolt/content/entries?sortBy=author&filter='); cy.get('.listing__row--list').eq(0).find('li').eq(1).should('contain', 'Admin'); @@ -26,13 +28,14 @@ describe('As an Admin I want to use record listing', () => { }) it('checks that an admin can filter content', () => { + // tag: ci cy.login(); cy.visit('/bolt/content/entries'); cy.get('div[class="card-header"]').should('contain', 'Contentlisting'); cy.get('#content-filter').type('a'); - cy.get('button[class="btn btn-secondary mb-0 "]').should('contain', 'Filter').click(); + cy.get('button[class="btn btn-secondary mb-0"]').should('contain', 'Filter').click(); cy.url().should('contain', '/bolt/content/entries?sortBy=&filter=a'); cy.get('.listing--container').its('length').should('eq', 10); @@ -41,7 +44,7 @@ describe('As an Admin I want to use record listing', () => { cy.get('#content-filter').clear(); cy.get('#content-filter').type('Entries'); - cy.get('button[class="btn btn-secondary mb-0 "]').should('contain', 'Filter').click(); + cy.get('button[class="btn btn-secondary mb-0"]').should('contain', 'Filter').click(); cy.url().should('contain', '/bolt/content/entries?sortBy=&filter=Entries'); cy.get('.listing--container').find('div[class="listing__row is-normal"]').find('div[class="listing__row--item is-details"]').find('a').should('contain', 'Entries'); @@ -49,17 +52,19 @@ describe('As an Admin I want to use record listing', () => { cy.get('#content-filter').clear(); cy.get('#content-filter').type(' '); - cy.get('button[class="btn btn-secondary mb-0 "]').should('contain', 'Filter').click(); + cy.get('button[class="btn btn-secondary mb-0"]').should('contain', 'Filter').click(); cy.url().should('contain', '/bolt/content/entries?sortBy=&filter='); cy.get('.listing--container').its('length').should('eq', 10); }) it('checks that a user can see the contenttype listing', () => { + // tag: ci cy.visit('/pages'); cy.get('article').its('length').should('eq', 6); }) it('checks that an admin can expand and compact the contenttype listing', () => { + // tag: ci cy.login(); cy.visit('/bolt/content/pages'); cy.get('button[title="Expanded"]').should('exist'); @@ -76,6 +81,7 @@ describe('As an Admin I want to use record listing', () => { }) it('checks that an admin can see the last edited records in the sidebar', () => { + // tag: ci cy.login(); cy.visit('/bolt/edit/74'); cy.get('button[name="save"]').eq(1).scrollIntoView(); @@ -88,18 +94,19 @@ describe('As an Admin I want to use record listing', () => { }) it('checks that an admin can see the settings menu items', () => { + // tag: ci cy.login(); cy.get('.admin__sidebar--menu').should('contain', 'Configuration'); - cy.get('#bolt--sidebar ul > li:nth-child(12) > a').trigger('mouseover'); - cy.get('#bolt--sidebar ul > li:nth-child(12) li:nth-child(1)').find('span').should('contain', 'View Configuration'); - cy.get('#bolt--sidebar ul li:nth-child(12) ul > li:nth-child(2) > a').find('span').should('contain', 'Users & Permissions'); - cy.get('#bolt--sidebar ul li:nth-child(12) ul > li:nth-child(3) > a').find('span').should('contain', 'Main Configuration'); - cy.get('#bolt--sidebar ul li:nth-child(12) ul > li:nth-child(4) > a').find('span').should('contain', 'Content Types'); - cy.get('#bolt--sidebar ul li:nth-child(12) ul > li:nth-child(5) > a').find('span').should('contain', 'Taxonomies'); - cy.get('#bolt--sidebar ul li:nth-child(12) ul > li:nth-child(6) > a').find('span').should('contain', 'Menu set up'); - cy.get('#bolt--sidebar ul li:nth-child(12) ul > li:nth-child(7) > a').find('span').should('contain', 'Routing configuration'); - cy.get('#bolt--sidebar ul li:nth-child(12) ul > li:nth-child(8) > a').find('span').should('contain', 'All configuration files'); + cy.get('#bolt--sidebar ul > li:nth-child(13) > a').trigger('mouseover'); + cy.get('#bolt--sidebar ul > li:nth-child(13) li:nth-child(1)').find('span').should('contain', 'View Configuration'); + cy.get('#bolt--sidebar ul li:nth-child(13) ul > li:nth-child(2) > a').find('span').should('contain', 'Users & Permissions'); + cy.get('#bolt--sidebar ul li:nth-child(13) ul > li:nth-child(3) > a').find('span').should('contain', 'Main Configuration'); + cy.get('#bolt--sidebar ul li:nth-child(13) ul > li:nth-child(4) > a').find('span').should('contain', 'Content Types'); + cy.get('#bolt--sidebar ul li:nth-child(13) ul > li:nth-child(5) > a').find('span').should('contain', 'Taxonomies'); + cy.get('#bolt--sidebar ul li:nth-child(13) ul > li:nth-child(6) > a').find('span').should('contain', 'Menu set up'); + cy.get('#bolt--sidebar ul li:nth-child(13) ul > li:nth-child(7) > a').find('span').should('contain', 'Routing configuration'); + cy.get('#bolt--sidebar ul li:nth-child(13) ul > li:nth-child(8) > a').find('span').should('contain', 'All configuration files'); }) }); diff --git a/tests/cypress/integration/record_localization.spec.js b/tests/cypress/integration/record_localization.spec.js index d7b67630f..9adcaa7ed 100644 --- a/tests/cypress/integration/record_localization.spec.js +++ b/tests/cypress/integration/record_localization.spec.js @@ -2,6 +2,7 @@ describe('Checks for localization', () => { it('checks that there\'s no localization link for contentype without locales', () => { + // tag: ci cy.login(); cy.findAllByText('Entries').click(); @@ -13,6 +14,7 @@ describe('Checks for localization', () => { }) it('checks that there\'s a localization link for contentype with locales', () => { + // tag: ci cy.login(); cy.findAllByText('Pages').click(); diff --git a/tests/cypress/integration/setcontent.spec.js b/tests/cypress/integration/setcontent.spec.js index 48f1d87fe..86ce8d58c 100644 --- a/tests/cypress/integration/setcontent.spec.js +++ b/tests/cypress/integration/setcontent.spec.js @@ -2,6 +2,7 @@ describe('As a user I want to see the results of Setcontent', () => { it('checks that the Setcontent page is visible as a user', () => { + // tag: ci cy.visit('/page/setcontent-test-page'); cy.get('#results-one').should('contain', 'yes'); cy.get('#results-two').should('contain', 'yes'); @@ -16,12 +17,14 @@ describe('As a user I want to see the results of Setcontent', () => { }) it('checks that the Setcontent order by taxonomy sortorder', () => { + // tag: ci cy.visit('/page/setcontent-test-page'); cy.get('#results-fourteen').should('contain', 'yes'); cy.get('#results-fifteen').should('contain', 'yes'); }) it('checks that the Setcontent is visible on a translated page as a user', () => { + // tag: ci cy.visit('/nl/page/setcontent-test-page'); cy.get('#results-one').should('contain', 'yes'); cy.get('#results-two').should('contain', 'yes'); diff --git a/tests/cypress/integration/view_users_tables.spec.js b/tests/cypress/integration/view_users_tables.spec.js index 876b17905..ee5bf2fa2 100644 --- a/tests/cypress/integration/view_users_tables.spec.js +++ b/tests/cypress/integration/view_users_tables.spec.js @@ -2,6 +2,7 @@ describe('View users and permissions', () => { it('checks that an admin can view users and permission', () => { + // tag: ci cy.login(); //Clear cache @@ -35,6 +36,7 @@ describe('View users and permissions', () => { }) it('checks that an admin can view the currently running sessions', () => { + // tag: ci cy.login(); cy.visit('/bolt/users'); diff --git a/tests/cypress/integration/widgets.spec.js b/tests/cypress/integration/widgets.spec.js index 0c592b875..f7f845b35 100644 --- a/tests/cypress/integration/widgets.spec.js +++ b/tests/cypress/integration/widgets.spec.js @@ -2,6 +2,7 @@ describe('As an admin I want to see the News Widget', () => { it('checks if News widget exists', () => { + // tag: ci cy.login(); cy.visit('/bolt/'); cy.get('#widget-news-widget').should('contain', 'Latest Bolt News'); diff --git a/tests/cypress/plugins/index.js b/tests/cypress/plugins/index.js index fe51f29d4..5bef9009c 100644 --- a/tests/cypress/plugins/index.js +++ b/tests/cypress/plugins/index.js @@ -19,4 +19,4 @@ module.exports = (on, config) => { // `on` is used to hook into various events Cypress emits // `config` is the resolved Cypress config -} +}; diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 3d5ce020d..a58f07a36 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -407,7 +407,7 @@ about.bolt_on_github - Bolt on Github + Bolt OSS on Github @@ -425,7 +425,7 @@ about.list_of_used_libraries - Below are the third party libraries that are used by Bolt. + Below are the third party libraries that are used by Bolt OSS. diff --git a/translations/messages.fr.xlf b/translations/messages.fr.xlf index 41af9cc60..8f5cb1108 100644 --- a/translations/messages.fr.xlf +++ b/translations/messages.fr.xlf @@ -407,7 +407,7 @@ about.bolt_on_github - Bolt sur Github + Bolt OSS sur Github @@ -425,7 +425,7 @@ about.list_of_used_libraries - Vous trouverez ci-dessous les bibliothèques tierces utilisées par Bolt. + Vous trouverez ci-dessous les bibliothèques tierces utilisées par Bolt OSS. @@ -684,7 +684,7 @@ caption.about_bolt - À propos de Bolt + À propos de Bolt OSS